Ingrese sus credenciales y haga clic en "Obtener Token" para comenzar.
+
+
+
+
+
+
+
+
+
Resultados
+
+
+
+
📥 Descargar Datos
+
+
+
+
+
+
+ Total de registros: 0
+
+
+
+
+
Lista de Candidatos
+
+
+
+
+
ID
+
Nombre
+
Correo
+
Teléfono
+
Género
+
Rango Edad
+
Tipo Identificación
+
País
+
Estado
+
Municipio
+
Colonia
+
Nivel Estudio
+
Giro
+
Empresa/Institución
+
ID Examen
+
Nombre Examen
+
Motivo
+
Calificación
+
Consentimiento Publicidad
+
Fecha Entrada
+
Fecha Salida
+
+
+
+
+
+
+
+
Respuesta JSON
+
Esperando respuesta...
+
+
+
+
+
+
Obtenga un token y haga una solicitud para ver los resultados aquí.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api_candidatos/openapi b/api_candidatos/openapi
new file mode 100644
index 0000000..2cd7bf9
--- /dev/null
+++ b/api_candidatos/openapi
@@ -0,0 +1,218 @@
+openapi: 3.0.3
+info:
+ title: API de Candidatos
+ description: |
+ API para gestionar información de candidatos con autenticación OAuth 2.0.
+ Permite obtener información detallada de candidatos incluyendo datos demográficos,
+ formación académica, exámenes y experiencia de servicio.
+ version: 1.0.0
+
+servers:
+ - url: /api
+ description: Servidor principal
+
+security:
+ - oauth2: []
+
+paths:
+ /oauth/token:
+ post:
+ summary: Obtener token de acceso OAuth 2.0
+ description: Endpoint para obtener un token de acceso utilizando credenciales de cliente
+ tags:
+ - Autenticación
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/x-www-form-urlencoded:
+ schema:
+ type: object
+ required:
+ - grant_type
+ - client_id
+ - client_secret
+ properties:
+ grant_type:
+ type: string
+ enum: [client_credentials]
+ description: Tipo de autorización OAuth 2.0
+ client_id:
+ type: string
+ description: Identificador del cliente
+ client_secret:
+ type: string
+ description: Secreto del cliente
+ scope:
+ type: string
+ description: Alcances solicitados (opcional)
+ responses:
+ '200':
+ description: Token de acceso generado exitosamente
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ token_type:
+ type: string
+ example: Bearer
+ expires_in:
+ type: integer
+ example: 3600
+ access_token:
+ type: string
+ example: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
+ '400':
+ description: Solicitud inválida o credenciales incorrectas
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: No autorizado
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /candidatos/obtenerCandidatos:
+ get:
+ summary: Obtener lista de candidatos
+ description: Devuelve un listado de todos los candidatos con información detallada
+ tags:
+ - Candidatos
+ responses:
+ '200':
+ description: Lista de candidatos obtenida correctamente
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Candidato'
+ '401':
+ description: No autorizado - Token de acceso inválido o expirado
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Error del servidor
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+components:
+ securitySchemes:
+ oauth2:
+ type: oauth2
+ flows:
+ clientCredentials:
+ tokenUrl: /api/oauth/token
+ scopes: {}
+
+ schemas:
+ Error:
+ type: object
+ properties:
+ error:
+ type: string
+ example: invalid_request
+ message:
+ type: string
+ example: El token de acceso proporcionado es inválido
+
+ Candidato:
+ type: object
+ properties:
+ id_candidato:
+ type: string
+ description: Identificador único del candidato
+ nombre_completo:
+ type: string
+ description: Nombre completo del candidato
+ contacto:
+ type: object
+ properties:
+ correo:
+ type: string
+ format: email
+ description: Correo electrónico del candidato
+ telefono:
+ type: string
+ description: Número telefónico del candidato
+ demograficos:
+ type: object
+ properties:
+ genero:
+ type: string
+ description: Género del candidato
+ rango_edad:
+ type: string
+ description: Rango de edad del candidato
+ tipo_identificacion:
+ type: string
+ description: Tipo de identificación del candidato
+ ubicacion:
+ type: object
+ properties:
+ pais:
+ type: string
+ description: País de residencia
+ estado:
+ type: string
+ description: Estado o provincia
+ municipio:
+ type: string
+ description: Municipio o ciudad
+ colonia:
+ type: string
+ description: Colonia o barrio
+ formacion:
+ type: object
+ properties:
+ nivel_estudio:
+ type: string
+ description: Nivel de estudios del candidato
+ giro:
+ type: string
+ description: Sector o giro de actividad
+ nombre_empresa_institucion:
+ type: string
+ description: Nombre de la empresa o institución donde trabaja/estudia
+ examen:
+ type: object
+ properties:
+ id_examen:
+ type: string
+ description: Identificador del examen
+ nombre_examen:
+ type: string
+ description: Nombre del examen realizado
+ motivo:
+ type: string
+ description: Motivo por el cual realizó el examen
+ experiencia_servicio:
+ type: object
+ properties:
+ calificacion_servicio:
+ type: integer
+ minimum: 0
+ maximum: 10
+ description: Calificación del servicio (0-10)
+ consentimiento_publicidad:
+ type: boolean
+ description: Consentimiento para recibir publicidad
+ fechas:
+ type: object
+ properties:
+ entrada:
+ type: string
+ format: date-time
+ description: Fecha y hora de entrada
+ salida:
+ type: string
+ format: date-time
+ description: Fecha y hora de salida
\ No newline at end of file
diff --git a/api_candidatos/private.key b/api_candidatos/private.key
new file mode 100644
index 0000000..9188a70
--- /dev/null
+++ b/api_candidatos/private.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDmIlzzZREHBOsT
+UYagVBBLo3OWOmR4xf/JTdE6LKte03MUL1340RCxqKnMHNddjgdfCs5nLPXq8cJz
+Bhmg/HvdNZbzxRAvdX3GRFEg5Clh6Nx0xLKqs+Luon8E1qr6a/d8y3TfGJ7CMsid
+wNNjTV2QI16R/ntPPcpy+mFBPXhzDNX4rJfvKq+dz7Py/SwOimLFhHAGhBbFv8v+
+1Yd2ZnFvQGUDZNEfmRJlyNznPW6aEa7vu7XuIuC7tTNCQ/cMGyQUgaJxWev3iH8r
+srH4I/TYyKuRUjv14Km3XgEvo5DwA8f0ZeXrgv0iSHe8+qbvf92DU2KBwZVS5Z3J
+GfP8sdazAgMBAAECggEAJwZ1v7qISCnv2S9OhpqqxsDZhYSya/6bkR32mIhhqStv
+TOF5bIu7an0hCiFr7gv7OQVCmiF4NFa59Dp5FyEpugnv5reotnuUkA4eudanI9jS
+paSDbcoidfgtVPs4NE4hwlJYJ8rrhSAKgCHmVuUUNDCjRVujunzOe2/1FRSg+9VD
+ivUjDa8GQ0Ydzt0wKM1GPnhUDJms+kM+mopRVTSqijFE3nr+JNX9ZiMIp4T3KpwR
+WVIjilFAU6658MHn8EGcIdTGU0CLcBSvZ6PdK7uMbjdgvX666AHJ7gjEFCj56lCF
+hwamExFMf1smHVg2HrC5hKj4o53CqNlbbIKS1GJh7QKBgQD5uBUBxYek2x/7OENf
+TsMX2ntseiM31cgnYFSE4bwodRqZ8A/+sjQKCWuTDOFoAj8oRsrkY9DlaL10Gr/i
+u4eXKU1/mVxXpefjiMoWx7ly0eeyRuvDx6TkIO/NdnY0ND5umSVAPx8VVOAUIOdZ
+w9e0E9URSj2qy3IfAoaPZgz6vQKBgQDr7C0Sf5oVJ2jxzJbsmGbPLgIIpvqMILdG
+UZGWM0XkhkkmkKI3hUR0qDtc2BlqZvWqvEGAgQfIU3Y3wTWVOgYhHbi+ylVxMvQQ
+c3waneWF2DbWgri9zG8GuSmug2x0GIjT/nOn7QSbpRrF71bu4+3oPMskzaMTgYTt
+LJkZCNLmLwKBgDQgKMJl6RqQYuydofKTDkY8ZOcP16ogBdeyU/Io7I3FY/geFDim
+Gha+QKZBWgvL7EMMA+4Ip+I7KtDBhKxfWL5E8NhhutTQ3MayFv0KU7uT9TlRdIU5
+d0HnXicVQzdCcIXFkfEHPAXH4b5R3/js2GnOeftR8+1i6j9u14e3VZ5BAoGBAKoi
+sgZrGxUyTI5Dunt5FHtIdJMEyB6R4VnGrTUiWL8K0GoNV86uPsXaJKU5+movQe8U
+wDAJ3TDsb46ZuSiapZzwMDD2/VMbKcNLZS5UvBcf67wanVvSuCajFZoSkP3QS6yG
+DaYGWZJdKMehaJHysbkPTniGC5qfhtr7lJTnNiBlAoGBAMeYwvc1e0BBktP0RsYg
+jwS8KgREYdM7nJf2hglJkpxJ5sg+7bmbyRLHFi8xz3VfNHNFOq9U6RFglhEUyEik
+xMnpk8a2CDkbQXuGhUYi/NDGCIetwsiUzMxxYwrCj0KNRbHwzr9lFOlykxsDdJjc
+xH9xnca2J8M3Rdp15gTMH7JG
+-----END PRIVATE KEY-----
diff --git a/api_candidatos/public.key b/api_candidatos/public.key
new file mode 100644
index 0000000..cfe6819
--- /dev/null
+++ b/api_candidatos/public.key
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5iJc82URBwTrE1GGoFQQ
+S6NzljpkeMX/yU3ROiyrXtNzFC9d+NEQsaipzBzXXY4HXwrOZyz16vHCcwYZoPx7
+3TWW88UQL3V9xkRRIOQpYejcdMSyqrPi7qJ/BNaq+mv3fMt03xiewjLIncDTY01d
+kCNekf57Tz3KcvphQT14cwzV+KyX7yqvnc+z8v0sDopixYRwBoQWxb/L/tWHdmZx
+b0BlA2TRH5kSZcjc5z1umhGu77u17iLgu7UzQkP3DBskFIGicVnr94h/K7Kx+CP0
+2MirkVI79eCpt14BL6OQ8APH9GXl64L9Ikh3vPqm73/dg1NigcGVUuWdyRnz/LHW
+swIDAQAB
+-----END PUBLIC KEY-----
\ No newline at end of file
diff --git a/api_candidatos/scripts/generate-keys.php b/api_candidatos/scripts/generate-keys.php
new file mode 100644
index 0000000..6e1fe34
--- /dev/null
+++ b/api_candidatos/scripts/generate-keys.php
@@ -0,0 +1,32 @@
+
+ 2048, // Tamaño de la clave
+ 'private_key_type' => OPENSSL_KEYTYPE_RSA,
+]);
+
+// Guardar la clave privada en un archivo
+openssl_pkey_export_to_file($privateKey, $appDir . '/private.key');
+
+echo "Clave privada generada en: " . $appDir . "/private.key\n";
+
+// Obtener los detalles de la clave privada para generar la clave pública
+$keyDetails = openssl_pkey_get_details($privateKey);
+
+// Guardar la clave pública en un archivo
+file_put_contents($appDir . '/public.key', $keyDetails['key']);
+
+echo "Clave pública generada en: " . $appDir . "/public.key\n";
+
+echo "¡Listo! Las claves se han generado correctamente.\n";
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Controllers/AuthController.php b/api_candidatos/src/OAuth/Controllers/AuthController.php
new file mode 100644
index 0000000..f08e479
--- /dev/null
+++ b/api_candidatos/src/OAuth/Controllers/AuthController.php
@@ -0,0 +1,66 @@
+enableGrantType(
+ new ClientCredentialsGrant(),
+ new \DateInterval('PT' . $config['access_token_ttl'] . 'S')
+ );
+
+ // Procesar petición
+ try {
+ $response = $server->respondToAccessTokenRequest(
+ \Slim\Psr7\Factory\ServerRequestFactory::createFromGlobals(),
+ new \Slim\Psr7\Response()
+ );
+
+ // Enviar respuesta
+ echo $response->getBody();
+
+ } catch (OAuthServerException $e) {
+ // Errores de OAuth
+ http_response_code($e->getHttpStatusCode());
+ echo json_encode([
+ 'error' => $e->getErrorType(),
+ 'message' => $e->getMessage()
+ ]);
+
+ } catch (\Exception $e) {
+ // Errores del servidor
+ http_response_code(500);
+ echo json_encode([
+ 'error' => 'server_error',
+ 'message' => $e->getMessage(), // MOSTRAR EL MENSAJE REAL
+ 'trace' => $e->getTraceAsString() // Opcional: útil para depurar
+ ]);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Entities/AccessTokenEntity.php b/api_candidatos/src/OAuth/Entities/AccessTokenEntity.php
new file mode 100644
index 0000000..fc5586d
--- /dev/null
+++ b/api_candidatos/src/OAuth/Entities/AccessTokenEntity.php
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Entities/ClientEntity.php b/api_candidatos/src/OAuth/Entities/ClientEntity.php
new file mode 100644
index 0000000..310eed1
--- /dev/null
+++ b/api_candidatos/src/OAuth/Entities/ClientEntity.php
@@ -0,0 +1,37 @@
+name = $name;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setRedirectUri($uri)
+ {
+ $this->redirectUri = $uri;
+ }
+
+ public function getRedirectUri()
+ {
+ return $this->redirectUri;
+ }
+
+ public function isConfidential()
+ {
+ return true;
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Entities/RefreshTokenEntity.php b/api_candidatos/src/OAuth/Entities/RefreshTokenEntity.php
new file mode 100644
index 0000000..c850da4
--- /dev/null
+++ b/api_candidatos/src/OAuth/Entities/RefreshTokenEntity.php
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Entities/ScopeEntity.php b/api_candidatos/src/OAuth/Entities/ScopeEntity.php
new file mode 100644
index 0000000..20f6cda
--- /dev/null
+++ b/api_candidatos/src/OAuth/Entities/ScopeEntity.php
@@ -0,0 +1,16 @@
+getIdentifier();
+ }
+}
+?>
diff --git a/api_candidatos/src/OAuth/Middleware/AuthMiddleware.php b/api_candidatos/src/OAuth/Middleware/AuthMiddleware.php
new file mode 100644
index 0000000..06a3540
--- /dev/null
+++ b/api_candidatos/src/OAuth/Middleware/AuthMiddleware.php
@@ -0,0 +1,51 @@
+validateAuthenticatedRequest($request);
+
+ return true;
+
+ } catch (OAuthServerException $e) {
+ // Token no válido
+ header('Content-Type: application/json; charset=UTF-8');
+ http_response_code($e->getHttpStatusCode());
+ echo json_encode([
+ 'error' => $e->getErrorType(),
+ 'message' => $e->getMessage()
+ ]);
+ exit;
+
+ } catch (\Exception $e) {
+ // Error del servidor
+ header('Content-Type: application/json; charset=UTF-8');
+ http_response_code(500);
+ echo json_encode([
+ 'error' => 'server_error',
+ 'message' => 'Se produjo un error en el servidor'
+ ]);
+ exit;
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Repositories/AccessTokenRepository.php b/api_candidatos/src/OAuth/Repositories/AccessTokenRepository.php
new file mode 100644
index 0000000..e2a6748
--- /dev/null
+++ b/api_candidatos/src/OAuth/Repositories/AccessTokenRepository.php
@@ -0,0 +1,77 @@
+conn = $conn;
+ }
+
+ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
+ {
+
+ $stmt = $this->conn->prepare(
+ 'INSERT INTO oauth_access_tokens (access_token, client_id, user_id, expires, scope) VALUES (?, ?, ?, ?, ?)'
+ );
+
+ $token = $accessTokenEntity->getIdentifier();
+ $clientId = $accessTokenEntity->getClient()->getIdentifier();
+ $userId = $accessTokenEntity->getUserIdentifier();
+ $expires = date('Y-m-d H:i:s', $accessTokenEntity->getExpiryDateTime()->getTimestamp());
+ $scopes = $this->scopesToString($accessTokenEntity->getScopes());
+
+ $stmt->bind_param('sssss', $token, $clientId, $userId, $expires, $scopes);
+ $stmt->execute();
+ }
+
+ public function revokeAccessToken($tokenId)
+ {
+ $stmt = $this->conn->prepare('DELETE FROM oauth_access_tokens WHERE access_token = ?');
+ $stmt->bind_param('s', $tokenId);
+ $stmt->execute();
+ }
+
+ public function isAccessTokenRevoked($tokenId)
+ {
+
+ $stmt = $this->conn->prepare('SELECT 1 FROM oauth_access_tokens WHERE access_token = ?');
+ $stmt->bind_param('s', $tokenId);
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ return $result->num_rows === 0;
+ }
+
+ public function getNewToken($client, array $scopes, $userIdentifier = null)
+ {
+ $accessToken = new \OAuth\Entities\AccessTokenEntity();
+ $accessToken->setClient($client);
+
+ if ($userIdentifier !== null) {
+ $accessToken->setUserIdentifier($userIdentifier);
+ }
+
+ foreach ($scopes as $scope) {
+ $accessToken->addScope($scope);
+ }
+
+ return $accessToken;
+ }
+
+ private function scopesToString(array $scopes)
+ {
+ return implode(' ', array_map(function ($scope) {
+ return $scope->getIdentifier();
+ }, $scopes));
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Repositories/ClientRepository.php b/api_candidatos/src/OAuth/Repositories/ClientRepository.php
new file mode 100644
index 0000000..f544ffa
--- /dev/null
+++ b/api_candidatos/src/OAuth/Repositories/ClientRepository.php
@@ -0,0 +1,63 @@
+conn = Database::connect();
+ }
+
+ public function getClientEntity($clientIdentifier)
+ {
+ $stmt = $this->conn->prepare('SELECT * FROM oauth_clients WHERE client_id = ?');
+ $stmt->bind_param('s', $clientIdentifier);
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ if ($result->num_rows === 0) {
+ return null;
+ }
+
+ $client = $result->fetch_assoc();
+
+ $clientEntity = new \OAuth\Entities\ClientEntity();
+ $clientEntity->setIdentifier($client['client_id']);
+ $clientEntity->setName($client['client_id']);
+
+ return $clientEntity;
+ }
+
+ public function validateClient($clientIdentifier, $clientSecret, $grantType)
+ {
+ $stmt = $this->conn->prepare('SELECT * FROM oauth_clients WHERE client_id = ?');
+ $stmt->bind_param('s', $clientIdentifier);
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ if ($result->num_rows === 0) {
+ return false;
+ }
+
+ $client = $result->fetch_assoc();
+
+ if (
+ $client['client_secret'] === $clientSecret &&
+ (
+ $client['grant_types'] === null ||
+ in_array($grantType, explode(',', $client['grant_types']))
+ )
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Repositories/RefreshTokenRepository.php b/api_candidatos/src/OAuth/Repositories/RefreshTokenRepository.php
new file mode 100644
index 0000000..02c54b8
--- /dev/null
+++ b/api_candidatos/src/OAuth/Repositories/RefreshTokenRepository.php
@@ -0,0 +1,55 @@
+getIdentifier();
+ $accessToken = $refreshTokenEntity->getAccessToken()->getIdentifier();
+ $expires = date('Y-m-d H:i:s', $refreshTokenEntity->getExpiryDateTime()->getTimestamp());
+ $clientId = $refreshTokenEntity->getAccessToken()->getClient()->getIdentifier();
+ $userId = $refreshTokenEntity->getAccessToken()->getUserIdentifier();
+
+ $stmt = $conn->prepare(
+ 'INSERT INTO oauth_refresh_tokens (refresh_token, access_token, client_id, user_id, expires) VALUES (?, ?, ?, ?, ?)'
+ );
+
+ $stmt->bind_param('sssss', $refreshToken, $accessToken, $clientId, $userId, $expires);
+ $stmt->execute();
+ }
+
+ public function revokeRefreshToken($tokenId)
+ {
+ global $conn;
+
+ $stmt = $conn->prepare('DELETE FROM oauth_refresh_tokens WHERE refresh_token = ?');
+ $stmt->bind_param('s', $tokenId);
+ $stmt->execute();
+ }
+
+ public function isRefreshTokenRevoked($tokenId)
+ {
+ global $conn;
+
+ $stmt = $conn->prepare('SELECT 1 FROM oauth_refresh_tokens WHERE refresh_token = ?');
+ $stmt->bind_param('s', $tokenId);
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ return $result->num_rows === 0;
+ }
+
+ public function getNewRefreshToken()
+ {
+ return new \OAuth\Entities\RefreshTokenEntity();
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Repositories/ScopeRepository.php b/api_candidatos/src/OAuth/Repositories/ScopeRepository.php
new file mode 100644
index 0000000..42af2f9
--- /dev/null
+++ b/api_candidatos/src/OAuth/Repositories/ScopeRepository.php
@@ -0,0 +1,55 @@
+conn = Database::connect();
+ }
+
+ public function getScopeEntityByIdentifier($identifier)
+ {
+ $stmt = $this->conn->prepare('SELECT * FROM oauth_scopes WHERE scope = ?');
+ $stmt->bind_param('s', $identifier);
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ if ($result->num_rows === 0) {
+ return null;
+ }
+
+ $scope = $result->fetch_assoc();
+
+ $scopeEntity = new ScopeEntity();
+ $scopeEntity->setIdentifier($scope['scope']);
+
+ return $scopeEntity;
+ }
+
+ public function finalizeScopes(array $scopes, $grantType, ClientEntityInterface $clientEntity, $userIdentifier = null)
+ {
+ if (count($scopes) === 0) {
+ $stmt = $this->conn->prepare('SELECT * FROM oauth_scopes WHERE is_default = 1');
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ while ($row = $result->fetch_assoc()) {
+ $scope = new ScopeEntity();
+ $scope->setIdentifier($row['scope']);
+ $scopes[] = $scope;
+ }
+ }
+
+ return $scopes;
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/OAuth/Routes/AuthRoutes.php b/api_candidatos/src/OAuth/Routes/AuthRoutes.php
new file mode 100644
index 0000000..4abf01e
--- /dev/null
+++ b/api_candidatos/src/OAuth/Routes/AuthRoutes.php
@@ -0,0 +1,20 @@
+ [
+ '/api/oauth/token' => [AuthController::class, 'token']
+ ]
+];
+
+if (isset($routes[$method][$path])) {
+ call_user_func($routes[$method][$path]);
+} else {
+ header("HTTP/1.1 404 Not Found");
+ echo json_encode(['error' => 'Ruta no encontrada']);
+ exit;
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/Utils/CorsHandler.php b/api_candidatos/src/Utils/CorsHandler.php
new file mode 100644
index 0000000..027226f
--- /dev/null
+++ b/api_candidatos/src/Utils/CorsHandler.php
@@ -0,0 +1,35 @@
+
\ No newline at end of file
diff --git a/api_candidatos/src/candidatos/controllers/CandidatoController.php b/api_candidatos/src/candidatos/controllers/CandidatoController.php
new file mode 100644
index 0000000..6369a3a
--- /dev/null
+++ b/api_candidatos/src/candidatos/controllers/CandidatoController.php
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/api_candidatos/src/candidatos/index.php b/api_candidatos/src/candidatos/index.php
new file mode 100644
index 0000000..2cde795
--- /dev/null
+++ b/api_candidatos/src/candidatos/index.php
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/api_candidatos/src/candidatos/models/Candidato.php b/api_candidatos/src/candidatos/models/Candidato.php
new file mode 100644
index 0000000..3a8ab67
--- /dev/null
+++ b/api_candidatos/src/candidatos/models/Candidato.php
@@ -0,0 +1,50 @@
+query($sql);
+ return $result->fetch_all(MYSQLI_ASSOC);
+ }
+}
+
+
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/candidatos/routes/CandidatoRoutes.php b/api_candidatos/src/candidatos/routes/CandidatoRoutes.php
new file mode 100644
index 0000000..8053485
--- /dev/null
+++ b/api_candidatos/src/candidatos/routes/CandidatoRoutes.php
@@ -0,0 +1,20 @@
+ [
+ '/api/candidatos/obtenerCandidatos' => [CandidatoController::class, 'index']
+ ]
+];
+
+if (isset($routes[$method][$path])) {
+ call_user_func($routes[$method][$path]);
+} else {
+ header("HTTP/1.1 404 Not Found");
+ echo "
Error 404
Ruta no encontrada: $path
";
+}
+
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/candidatos/services/CandidatoService.php b/api_candidatos/src/candidatos/services/CandidatoService.php
new file mode 100644
index 0000000..c18ad3e
--- /dev/null
+++ b/api_candidatos/src/candidatos/services/CandidatoService.php
@@ -0,0 +1,52 @@
+ $candidato["id_candidato"],
+ "nombre_completo" => $candidato["nombre_completo"],
+ "contacto" => [
+ "correo" => $candidato["correo"],
+ "telefono" => $candidato["telefono"]
+ ],
+ "demograficos" => [
+ "genero" => $candidato["genero"],
+ "rango_edad" => $candidato["rango_edad"],
+ "tipo_identificacion" => $candidato["tipo_identificacion"],
+ "ubicacion" => [
+ "pais" => $candidato["pais"],
+ "estado" => $candidato["estado"],
+ "municipio" => $candidato["municipio"],
+ "colonia" => $candidato["colonia"]
+ ]
+ ],
+ "formacion" => [
+ "nivel_estudio" => $candidato["nivel_estudio"],
+ "giro" => $candidato["giro"],
+ "nombre_empresa_institucion" => $candidato["nombre_empresa_institucion"]
+ ],
+ "examen" => [
+ "id_examen" => $candidato["id_examen"],
+ "nombre_examen" => $candidato["nombre_examen"],
+ "motivo" => $candidato["motivo_examen"]
+ ],
+ "experiencia_servicio" => [
+ "calificacion_servicio" => (int)$candidato["calificacion_servicio"],
+ "consentimiento_publicidad" => $candidato["consentimiento_publicidad"] == "1"
+ ],
+ "fechas" => [
+ "entrada" => $candidato["fecha_entrada"],
+ "salida" => $candidato["fecha_salida"]
+ ]
+ ];
+ }
+
+ return $candidatos;
+ }
+}
+?>
diff --git a/api_candidatos/src/config/database.php b/api_candidatos/src/config/database.php
new file mode 100644
index 0000000..8ab2947
--- /dev/null
+++ b/api_candidatos/src/config/database.php
@@ -0,0 +1,24 @@
+connect_error) {
+ die("Error de conexión a la base de datos: " . $conn->connect_error);
+ }
+
+ $conn->set_charset("utf8mb4");
+
+ return $conn;
+ }
+}
+?>
\ No newline at end of file
diff --git a/api_candidatos/src/config/oauth.php b/api_candidatos/src/config/oauth.php
new file mode 100644
index 0000000..4667285
--- /dev/null
+++ b/api_candidatos/src/config/oauth.php
@@ -0,0 +1,10 @@
+ __DIR__ . '/../../private.key',
+ 'public_key_path' => __DIR__ . '/../../public.key',
+ 'encryption_key' => 'lkj7LKJ98y0897YJHjh6&%^',
+ 'access_token_ttl' => 3600, // 1 hora
+ 'refresh_token_ttl' => 86400 * 30, // 30 días
+];
+?>
\ No newline at end of file
diff --git a/api_candidatos/vendor/autoload.php b/api_candidatos/vendor/autoload.php
new file mode 100644
index 0000000..77b62ab
--- /dev/null
+++ b/api_candidatos/vendor/autoload.php
@@ -0,0 +1,22 @@
+realpath = realpath($opened_path) ?: $opened_path;
+ $opened_path = $this->realpath;
+ $this->handle = fopen($this->realpath, $mode);
+ $this->position = 0;
+
+ return (bool) $this->handle;
+ }
+
+ public function stream_read($count)
+ {
+ $data = fread($this->handle, $count);
+
+ if ($this->position === 0) {
+ $data = preg_replace('{^#!.*\r?\n}', '', $data);
+ }
+
+ $this->position += strlen($data);
+
+ return $data;
+ }
+
+ public function stream_cast($castAs)
+ {
+ return $this->handle;
+ }
+
+ public function stream_close()
+ {
+ fclose($this->handle);
+ }
+
+ public function stream_lock($operation)
+ {
+ return $operation ? flock($this->handle, $operation) : true;
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ if (0 === fseek($this->handle, $offset, $whence)) {
+ $this->position = ftell($this->handle);
+ return true;
+ }
+
+ return false;
+ }
+
+ public function stream_tell()
+ {
+ return $this->position;
+ }
+
+ public function stream_eof()
+ {
+ return feof($this->handle);
+ }
+
+ public function stream_stat()
+ {
+ return array();
+ }
+
+ public function stream_set_option($option, $arg1, $arg2)
+ {
+ return true;
+ }
+
+ public function url_stat($path, $flags)
+ {
+ $path = substr($path, 17);
+ if (file_exists($path)) {
+ return stat($path);
+ }
+
+ return false;
+ }
+ }
+ }
+
+ if (
+ (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
+ || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
+ ) {
+ return include("phpvfscomposer://" . __DIR__ . '/..'.'/defuse/php-encryption/bin/generate-defuse-key');
+ }
+}
+
+return include __DIR__ . '/..'.'/defuse/php-encryption/bin/generate-defuse-key';
diff --git a/api_candidatos/vendor/bin/generate-defuse-key.bat b/api_candidatos/vendor/bin/generate-defuse-key.bat
new file mode 100644
index 0000000..02cc0c1
--- /dev/null
+++ b/api_candidatos/vendor/bin/generate-defuse-key.bat
@@ -0,0 +1,5 @@
+@ECHO OFF
+setlocal DISABLEDELAYEDEXPANSION
+SET BIN_TARGET=%~dp0/generate-defuse-key
+SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
+php "%BIN_TARGET%" %*
diff --git a/api_candidatos/vendor/composer/ClassLoader.php b/api_candidatos/vendor/composer/ClassLoader.php
new file mode 100644
index 0000000..7824d8f
--- /dev/null
+++ b/api_candidatos/vendor/composer/ClassLoader.php
@@ -0,0 +1,579 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @see https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ /** @var \Closure(string):void */
+ private static $includeFile;
+
+ /** @var string|null */
+ private $vendorDir;
+
+ // PSR-4
+ /**
+ * @var array>
+ */
+ private $prefixLengthsPsr4 = array();
+ /**
+ * @var array>
+ */
+ private $prefixDirsPsr4 = array();
+ /**
+ * @var list
+ */
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ /**
+ * List of PSR-0 prefixes
+ *
+ * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
+ *
+ * @var array>>
+ */
+ private $prefixesPsr0 = array();
+ /**
+ * @var list
+ */
+ private $fallbackDirsPsr0 = array();
+
+ /** @var bool */
+ private $useIncludePath = false;
+
+ /**
+ * @var array
+ */
+ private $classMap = array();
+
+ /** @var bool */
+ private $classMapAuthoritative = false;
+
+ /**
+ * @var array
+ */
+ private $missingClasses = array();
+
+ /** @var string|null */
+ private $apcuPrefix;
+
+ /**
+ * @var array
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param string|null $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ self::initializeIncludeClosure();
+ }
+
+ /**
+ * @return array>
+ */
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+ }
+
+ return array();
+ }
+
+ /**
+ * @return array>
+ */
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ /**
+ * @return list
+ */
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ /**
+ * @return list
+ */
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ /**
+ * @return array Array of classname => path
+ */
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ *
+ * @return void
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param list|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ $paths = (array) $paths;
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param list|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ $paths = (array) $paths;
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param list|string $paths The PSR-0 base directories
+ *
+ * @return void
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param list|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ *
+ * @return void
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ *
+ * @return void
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ *
+ * @return void
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ *
+ * @return void
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return true|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ $includeFile = self::$includeFile;
+ $includeFile($file);
+
+ return true;
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ /**
+ * Returns the currently registered loaders keyed by their corresponding vendor directories.
+ *
+ * @return array
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return void
+ */
+ private static function initializeIncludeClosure()
+ {
+ if (self::$includeFile !== null) {
+ return;
+ }
+
+ /**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ */
+ self::$includeFile = \Closure::bind(static function($file) {
+ include $file;
+ }, null, null);
+ }
+}
diff --git a/api_candidatos/vendor/composer/InstalledVersions.php b/api_candidatos/vendor/composer/InstalledVersions.php
new file mode 100644
index 0000000..2052022
--- /dev/null
+++ b/api_candidatos/vendor/composer/InstalledVersions.php
@@ -0,0 +1,396 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+ /**
+ * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
+ * @internal
+ */
+ private static $selfDir = null;
+
+ /**
+ * @var mixed[]|null
+ * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null
+ */
+ private static $installed;
+
+ /**
+ * @var bool
+ */
+ private static $installedIsLocalDir;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @psalm-var array}>
+ */
+ private static $installedByVendor = array();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints((string) $constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
+ */
+ public static function getRootPackage()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+ * @return array[]
+ * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}
+ */
+ public static function getRawData()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
+ *
+ * @return array[]
+ * @psalm-return list}>
+ */
+ public static function getAllRawData()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data
+ */
+ public static function reload($data)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+
+ // when using reload, we disable the duplicate protection to ensure that self::$installed data is
+ // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
+ // so we have to assume it does not, and that may result in duplicate data being returned when listing
+ // all installed packages for example
+ self::$installedIsLocalDir = false;
+ }
+
+ /**
+ * @return string
+ */
+ private static function getSelfDir()
+ {
+ if (self::$selfDir === null) {
+ self::$selfDir = strtr(__DIR__, '\\', '/');
+ }
+
+ return self::$selfDir;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return list}>
+ */
+ private static function getInstalled()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+ $copiedLocalDir = false;
+
+ if (self::$canGetVendors) {
+ $selfDir = self::getSelfDir();
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ $vendorDir = strtr($vendorDir, '\\', '/');
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */
+ $required = require $vendorDir.'/composer/installed.php';
+ self::$installedByVendor[$vendorDir] = $required;
+ $installed[] = $required;
+ if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
+ self::$installed = $required;
+ self::$installedIsLocalDir = true;
+ }
+ }
+ if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
+ $copiedLocalDir = true;
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */
+ $required = require __DIR__ . '/installed.php';
+ self::$installed = $required;
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ if (self::$installed !== array() && !$copiedLocalDir) {
+ $installed[] = self::$installed;
+ }
+
+ return $installed;
+ }
+}
diff --git a/api_candidatos/vendor/composer/LICENSE b/api_candidatos/vendor/composer/LICENSE
new file mode 100644
index 0000000..f27399a
--- /dev/null
+++ b/api_candidatos/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/api_candidatos/vendor/composer/autoload_classmap.php b/api_candidatos/vendor/composer/autoload_classmap.php
new file mode 100644
index 0000000..5490b88
--- /dev/null
+++ b/api_candidatos/vendor/composer/autoload_classmap.php
@@ -0,0 +1,15 @@
+ $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+ 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
+ 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
+ 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+ 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
+);
diff --git a/api_candidatos/vendor/composer/autoload_files.php b/api_candidatos/vendor/composer/autoload_files.php
new file mode 100644
index 0000000..fc44162
--- /dev/null
+++ b/api_candidatos/vendor/composer/autoload_files.php
@@ -0,0 +1,11 @@
+ $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
+ 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
+);
diff --git a/api_candidatos/vendor/composer/autoload_namespaces.php b/api_candidatos/vendor/composer/autoload_namespaces.php
new file mode 100644
index 0000000..15a2ff3
--- /dev/null
+++ b/api_candidatos/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+ array($vendorDir . '/symfony/polyfill-php80'),
+ 'StellaMaris\\Clock\\' => array($vendorDir . '/stella-maris/clock/src'),
+ 'Slim\\Psr7\\' => array($vendorDir . '/slim/psr7/src'),
+ 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
+ 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
+ 'OAuth\\' => array($baseDir . '/src/OAuth'),
+ 'League\\Uri\\' => array($vendorDir . '/league/uri/src', $vendorDir . '/league/uri-interfaces/src'),
+ 'League\\OAuth2\\Server\\' => array($vendorDir . '/league/oauth2-server/src'),
+ 'League\\Event\\' => array($vendorDir . '/league/event/src'),
+ 'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
+ 'Lcobucci\\Clock\\' => array($vendorDir . '/lcobucci/clock/src'),
+ 'Fig\\Http\\Message\\' => array($vendorDir . '/fig/http-message-util/src'),
+ 'Defuse\\Crypto\\' => array($vendorDir . '/defuse/php-encryption/src'),
+ 'Config\\' => array($baseDir . '/src/Config'),
+);
diff --git a/api_candidatos/vendor/composer/autoload_real.php b/api_candidatos/vendor/composer/autoload_real.php
new file mode 100644
index 0000000..e14fffe
--- /dev/null
+++ b/api_candidatos/vendor/composer/autoload_real.php
@@ -0,0 +1,50 @@
+register(true);
+
+ $filesToLoad = \Composer\Autoload\ComposerStaticInitd32a508174e07df637170f00512a95ed::$files;
+ $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
+ if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+ $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+ require $file;
+ }
+ }, null, null);
+ foreach ($filesToLoad as $fileIdentifier => $file) {
+ $requireFile($fileIdentifier, $file);
+ }
+
+ return $loader;
+ }
+}
diff --git a/api_candidatos/vendor/composer/autoload_static.php b/api_candidatos/vendor/composer/autoload_static.php
new file mode 100644
index 0000000..cdb0895
--- /dev/null
+++ b/api_candidatos/vendor/composer/autoload_static.php
@@ -0,0 +1,131 @@
+ __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
+ 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
+ );
+
+ public static $prefixLengthsPsr4 = array (
+ 'S' =>
+ array (
+ 'Symfony\\Polyfill\\Php80\\' => 23,
+ 'StellaMaris\\Clock\\' => 18,
+ 'Slim\\Psr7\\' => 10,
+ ),
+ 'P' =>
+ array (
+ 'Psr\\Http\\Message\\' => 17,
+ 'Psr\\Clock\\' => 10,
+ ),
+ 'O' =>
+ array (
+ 'OAuth\\' => 6,
+ ),
+ 'L' =>
+ array (
+ 'League\\Uri\\' => 11,
+ 'League\\OAuth2\\Server\\' => 21,
+ 'League\\Event\\' => 13,
+ 'Lcobucci\\JWT\\' => 13,
+ 'Lcobucci\\Clock\\' => 15,
+ ),
+ 'F' =>
+ array (
+ 'Fig\\Http\\Message\\' => 17,
+ ),
+ 'D' =>
+ array (
+ 'Defuse\\Crypto\\' => 14,
+ ),
+ 'C' =>
+ array (
+ 'Config\\' => 7,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'Symfony\\Polyfill\\Php80\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
+ ),
+ 'StellaMaris\\Clock\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/stella-maris/clock/src',
+ ),
+ 'Slim\\Psr7\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/slim/psr7/src',
+ ),
+ 'Psr\\Http\\Message\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/http-factory/src',
+ 1 => __DIR__ . '/..' . '/psr/http-message/src',
+ ),
+ 'Psr\\Clock\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/clock/src',
+ ),
+ 'OAuth\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/src/OAuth',
+ ),
+ 'League\\Uri\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/league/uri/src',
+ 1 => __DIR__ . '/..' . '/league/uri-interfaces/src',
+ ),
+ 'League\\OAuth2\\Server\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/league/oauth2-server/src',
+ ),
+ 'League\\Event\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/league/event/src',
+ ),
+ 'Lcobucci\\JWT\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/lcobucci/jwt/src',
+ ),
+ 'Lcobucci\\Clock\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/lcobucci/clock/src',
+ ),
+ 'Fig\\Http\\Message\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/fig/http-message-util/src',
+ ),
+ 'Defuse\\Crypto\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/defuse/php-encryption/src',
+ ),
+ 'Config\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/src/Config',
+ ),
+ );
+
+ public static $classMap = array (
+ 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+ 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
+ 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
+ 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+ 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInitd32a508174e07df637170f00512a95ed::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInitd32a508174e07df637170f00512a95ed::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInitd32a508174e07df637170f00512a95ed::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/api_candidatos/vendor/composer/installed.json b/api_candidatos/vendor/composer/installed.json
new file mode 100644
index 0000000..3d303d7
--- /dev/null
+++ b/api_candidatos/vendor/composer/installed.json
@@ -0,0 +1,1089 @@
+{
+ "packages": [
+ {
+ "name": "defuse/php-encryption",
+ "version": "v2.4.0",
+ "version_normalized": "2.4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/defuse/php-encryption.git",
+ "reference": "f53396c2d34225064647a05ca76c1da9d99e5828"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/defuse/php-encryption/zipball/f53396c2d34225064647a05ca76c1da9d99e5828",
+ "reference": "f53396c2d34225064647a05ca76c1da9d99e5828",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "paragonie/random_compat": ">= 2",
+ "php": ">=5.6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5|^6|^7|^8|^9|^10",
+ "yoast/phpunit-polyfills": "^2.0.0"
+ },
+ "time": "2023-06-19T06:10:36+00:00",
+ "bin": [
+ "bin/generate-defuse-key"
+ ],
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Defuse\\Crypto\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Hornby",
+ "email": "taylor@defuse.ca",
+ "homepage": "https://defuse.ca/"
+ },
+ {
+ "name": "Scott Arciszewski",
+ "email": "info@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "Secure PHP Encryption Library",
+ "keywords": [
+ "aes",
+ "authenticated encryption",
+ "cipher",
+ "crypto",
+ "cryptography",
+ "encrypt",
+ "encryption",
+ "openssl",
+ "security",
+ "symmetric key cryptography"
+ ],
+ "support": {
+ "issues": "https://github.com/defuse/php-encryption/issues",
+ "source": "https://github.com/defuse/php-encryption/tree/v2.4.0"
+ },
+ "install-path": "../defuse/php-encryption"
+ },
+ {
+ "name": "fig/http-message-util",
+ "version": "1.1.5",
+ "version_normalized": "1.1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message-util.git",
+ "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765",
+ "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3 || ^7.0 || ^8.0"
+ },
+ "suggest": {
+ "psr/http-message": "The package containing the PSR-7 interfaces"
+ },
+ "time": "2020-11-24T22:02:12+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Fig\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/http-message-util/issues",
+ "source": "https://github.com/php-fig/http-message-util/tree/1.1.5"
+ },
+ "install-path": "../fig/http-message-util"
+ },
+ {
+ "name": "lcobucci/clock",
+ "version": "2.3.0",
+ "version_normalized": "2.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/lcobucci/clock.git",
+ "reference": "c7aadcd6fd97ed9e199114269c0be3f335e38876"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/lcobucci/clock/zipball/c7aadcd6fd97ed9e199114269c0be3f335e38876",
+ "reference": "c7aadcd6fd97ed9e199114269c0be3f335e38876",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~8.1.0 || ~8.2.0",
+ "stella-maris/clock": "^0.1.7"
+ },
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
+ "require-dev": {
+ "infection/infection": "^0.26",
+ "lcobucci/coding-standard": "^9.0",
+ "phpstan/extension-installer": "^1.2",
+ "phpstan/phpstan": "^1.9.4",
+ "phpstan/phpstan-deprecation-rules": "^1.1.1",
+ "phpstan/phpstan-phpunit": "^1.3.2",
+ "phpstan/phpstan-strict-rules": "^1.4.4",
+ "phpunit/phpunit": "^9.5.27"
+ },
+ "time": "2022-12-19T14:38:11+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\Clock\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com"
+ }
+ ],
+ "description": "Yet another clock abstraction",
+ "support": {
+ "issues": "https://github.com/lcobucci/clock/issues",
+ "source": "https://github.com/lcobucci/clock/tree/2.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/lcobucci",
+ "type": "github"
+ },
+ {
+ "url": "https://www.patreon.com/lcobucci",
+ "type": "patreon"
+ }
+ ],
+ "install-path": "../lcobucci/clock"
+ },
+ {
+ "name": "lcobucci/jwt",
+ "version": "4.0.4",
+ "version_normalized": "4.0.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/lcobucci/jwt.git",
+ "reference": "55564265fddf810504110bd68ca311932324b0e9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/lcobucci/jwt/zipball/55564265fddf810504110bd68ca311932324b0e9",
+ "reference": "55564265fddf810504110bd68ca311932324b0e9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "ext-openssl": "*",
+ "lcobucci/clock": "^2.0",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "infection/infection": "^0.20",
+ "lcobucci/coding-standard": "^6.0",
+ "mikey179/vfsstream": "^1.6",
+ "phpbench/phpbench": "^0.17",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^0.12",
+ "phpstan/phpstan-deprecation-rules": "^0.12",
+ "phpstan/phpstan-phpunit": "^0.12",
+ "phpstan/phpstan-strict-rules": "^0.12",
+ "phpunit/php-invoker": "^3.1",
+ "phpunit/phpunit": "^9.4"
+ },
+ "time": "2021-09-28T19:18:28+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\JWT\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+ "keywords": [
+ "JWS",
+ "jwt"
+ ],
+ "support": {
+ "issues": "https://github.com/lcobucci/jwt/issues",
+ "source": "https://github.com/lcobucci/jwt/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/lcobucci",
+ "type": "github"
+ },
+ {
+ "url": "https://www.patreon.com/lcobucci",
+ "type": "patreon"
+ }
+ ],
+ "install-path": "../lcobucci/jwt"
+ },
+ {
+ "name": "league/event",
+ "version": "2.3.0",
+ "version_normalized": "2.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/event.git",
+ "reference": "062ebb450efbe9a09bc2478e89b7c933875b0935"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/event/zipball/062ebb450efbe9a09bc2478e89b7c933875b0935",
+ "reference": "062ebb450efbe9a09bc2478e89b7c933875b0935",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "henrikbjorn/phpspec-code-coverage": "~1.0.1",
+ "phpspec/phpspec": "^2.2"
+ },
+ "time": "2025-03-14T19:51:10+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "League\\Event\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Frank de Jonge",
+ "email": "info@frenky.net"
+ }
+ ],
+ "description": "Event package",
+ "keywords": [
+ "emitter",
+ "event",
+ "listener"
+ ],
+ "support": {
+ "issues": "https://github.com/thephpleague/event/issues",
+ "source": "https://github.com/thephpleague/event/tree/2.3.0"
+ },
+ "install-path": "../league/event"
+ },
+ {
+ "name": "league/oauth2-server",
+ "version": "8.4.3",
+ "version_normalized": "8.4.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/oauth2-server.git",
+ "reference": "8a59a84450f0f64adcea8e1f8c0e0d9dfc8887d1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/8a59a84450f0f64adcea8e1f8c0e0d9dfc8887d1",
+ "reference": "8a59a84450f0f64adcea8e1f8c0e0d9dfc8887d1",
+ "shasum": ""
+ },
+ "require": {
+ "defuse/php-encryption": "^2.2.1",
+ "ext-json": "*",
+ "ext-openssl": "*",
+ "lcobucci/jwt": "^3.4.6 || ^4.0.4",
+ "league/event": "^2.2",
+ "league/uri": "^6.4",
+ "php": "^7.2 || ^8.0",
+ "psr/http-message": "^1.0.1"
+ },
+ "replace": {
+ "league/oauth2server": "*",
+ "lncd/oauth2": "*"
+ },
+ "require-dev": {
+ "laminas/laminas-diactoros": "^2.4.1",
+ "phpstan/phpstan": "^0.12.57",
+ "phpstan/phpstan-phpunit": "^0.12.16",
+ "phpunit/phpunit": "^8.5.13",
+ "roave/security-advisories": "dev-master"
+ },
+ "time": "2024-12-18T00:21:54+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "League\\OAuth2\\Server\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Alex Bilbie",
+ "email": "hello@alexbilbie.com",
+ "homepage": "http://www.alexbilbie.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Andy Millington",
+ "email": "andrew@noexceptions.io",
+ "homepage": "https://www.noexceptions.io",
+ "role": "Developer"
+ }
+ ],
+ "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
+ "homepage": "https://oauth2.thephpleague.com/",
+ "keywords": [
+ "Authentication",
+ "api",
+ "auth",
+ "authorisation",
+ "authorization",
+ "oauth",
+ "oauth 2",
+ "oauth 2.0",
+ "oauth2",
+ "protect",
+ "resource",
+ "secure",
+ "server"
+ ],
+ "support": {
+ "issues": "https://github.com/thephpleague/oauth2-server/issues",
+ "source": "https://github.com/thephpleague/oauth2-server/tree/8.4.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sephster",
+ "type": "github"
+ }
+ ],
+ "install-path": "../league/oauth2-server"
+ },
+ {
+ "name": "league/uri",
+ "version": "6.8.0",
+ "version_normalized": "6.8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/uri.git",
+ "reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/uri/zipball/a700b4656e4c54371b799ac61e300ab25a2d1d39",
+ "reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "league/uri-interfaces": "^2.3",
+ "php": "^8.1",
+ "psr/http-message": "^1.0.1"
+ },
+ "conflict": {
+ "league/uri-schemes": "^1.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^v3.9.5",
+ "nyholm/psr7": "^1.5.1",
+ "php-http/psr7-integration-tests": "^1.1.1",
+ "phpbench/phpbench": "^1.2.6",
+ "phpstan/phpstan": "^1.8.5",
+ "phpstan/phpstan-deprecation-rules": "^1.0",
+ "phpstan/phpstan-phpunit": "^1.1.1",
+ "phpstan/phpstan-strict-rules": "^1.4.3",
+ "phpunit/phpunit": "^9.5.24",
+ "psr/http-factory": "^1.0.1"
+ },
+ "suggest": {
+ "ext-fileinfo": "Needed to create Data URI from a filepath",
+ "ext-intl": "Needed to improve host validation",
+ "league/uri-components": "Needed to easily manipulate URI objects",
+ "psr/http-factory": "Needed to use the URI factory"
+ },
+ "time": "2022-09-13T19:58:47+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "League\\Uri\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ignace Nyamagana Butera",
+ "email": "nyamsprod@gmail.com",
+ "homepage": "https://nyamsprod.com"
+ }
+ ],
+ "description": "URI manipulation library",
+ "homepage": "https://uri.thephpleague.com",
+ "keywords": [
+ "data-uri",
+ "file-uri",
+ "ftp",
+ "hostname",
+ "http",
+ "https",
+ "middleware",
+ "parse_str",
+ "parse_url",
+ "psr-7",
+ "query-string",
+ "querystring",
+ "rfc3986",
+ "rfc3987",
+ "rfc6570",
+ "uri",
+ "uri-template",
+ "url",
+ "ws"
+ ],
+ "support": {
+ "docs": "https://uri.thephpleague.com",
+ "forum": "https://thephpleague.slack.com",
+ "issues": "https://github.com/thephpleague/uri/issues",
+ "source": "https://github.com/thephpleague/uri/tree/6.8.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/nyamsprod",
+ "type": "github"
+ }
+ ],
+ "install-path": "../league/uri"
+ },
+ {
+ "name": "league/uri-interfaces",
+ "version": "2.3.0",
+ "version_normalized": "2.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/uri-interfaces.git",
+ "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/00e7e2943f76d8cb50c7dfdc2f6dee356e15e383",
+ "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "phpstan/phpstan": "^0.12.90",
+ "phpstan/phpstan-phpunit": "^0.12.19",
+ "phpstan/phpstan-strict-rules": "^0.12.9",
+ "phpunit/phpunit": "^8.5.15 || ^9.5"
+ },
+ "suggest": {
+ "ext-intl": "to use the IDNA feature",
+ "symfony/intl": "to use the IDNA feature via Symfony Polyfill"
+ },
+ "time": "2021-06-28T04:27:21+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "League\\Uri\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ignace Nyamagana Butera",
+ "email": "nyamsprod@gmail.com",
+ "homepage": "https://nyamsprod.com"
+ }
+ ],
+ "description": "Common interface for URI representation",
+ "homepage": "http://github.com/thephpleague/uri-interfaces",
+ "keywords": [
+ "rfc3986",
+ "rfc3987",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "issues": "https://github.com/thephpleague/uri-interfaces/issues",
+ "source": "https://github.com/thephpleague/uri-interfaces/tree/2.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/nyamsprod",
+ "type": "github"
+ }
+ ],
+ "install-path": "../league/uri-interfaces"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.100",
+ "version_normalized": "9.99.100.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "time": "2020-10-15T08:29:30+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "install-path": "../paragonie/random_compat"
+ },
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "install-path": "../psr/clock"
+ },
+ {
+ "name": "psr/http-factory",
+ "version": "1.1.0",
+ "version_normalized": "1.1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-factory.git",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "time": "2024-04-15T12:06:14+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
+ "keywords": [
+ "factory",
+ "http",
+ "message",
+ "psr",
+ "psr-17",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-factory"
+ },
+ "install-path": "../psr/http-factory"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.1",
+ "version_normalized": "1.1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+ "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "time": "2023-04-04T09:50:52+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-message/tree/1.1"
+ },
+ "install-path": "../psr/http-message"
+ },
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "version_normalized": "3.0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "time": "2019-03-08T08:55:37+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders.",
+ "support": {
+ "issues": "https://github.com/ralouphie/getallheaders/issues",
+ "source": "https://github.com/ralouphie/getallheaders/tree/develop"
+ },
+ "install-path": "../ralouphie/getallheaders"
+ },
+ {
+ "name": "slim/psr7",
+ "version": "1.7.1",
+ "version_normalized": "1.7.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/slimphp/Slim-Psr7.git",
+ "reference": "fe98653e7983010aa85c1d137c9b9ad5a1cd187d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/fe98653e7983010aa85c1d137c9b9ad5a1cd187d",
+ "reference": "fe98653e7983010aa85c1d137c9b9ad5a1cd187d",
+ "shasum": ""
+ },
+ "require": {
+ "fig/http-message-util": "^1.1.5",
+ "php": "^8.0",
+ "psr/http-factory": "^1.1",
+ "psr/http-message": "^1.0 || ^2.0",
+ "ralouphie/getallheaders": "^3.0",
+ "symfony/polyfill-php80": "^1.29"
+ },
+ "provide": {
+ "psr/http-factory-implementation": "^1.0",
+ "psr/http-message-implementation": "^1.0 || ^2.0"
+ },
+ "require-dev": {
+ "adriansuter/php-autoload-override": "^1.4",
+ "ext-json": "*",
+ "http-interop/http-factory-tests": "^1.0 || ^2.0",
+ "php-http/psr7-integration-tests": "^1.4",
+ "phpspec/prophecy": "^1.19",
+ "phpspec/prophecy-phpunit": "^2.2",
+ "phpstan/phpstan": "^2.1",
+ "phpunit/phpunit": "^9.6 || ^10",
+ "squizlabs/php_codesniffer": "^3.10"
+ },
+ "time": "2025-05-13T14:24:12+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Slim\\Psr7\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Josh Lockhart",
+ "email": "hello@joshlockhart.com",
+ "homepage": "https://joshlockhart.com"
+ },
+ {
+ "name": "Andrew Smith",
+ "email": "a.smith@silentworks.co.uk",
+ "homepage": "https://silentworks.co.uk"
+ },
+ {
+ "name": "Rob Allen",
+ "email": "rob@akrabat.com",
+ "homepage": "https://akrabat.com"
+ },
+ {
+ "name": "Pierre Berube",
+ "email": "pierre@lgse.com",
+ "homepage": "https://www.lgse.com"
+ }
+ ],
+ "description": "Strict PSR-7 implementation",
+ "homepage": "https://www.slimframework.com",
+ "keywords": [
+ "http",
+ "psr-7",
+ "psr7"
+ ],
+ "support": {
+ "issues": "https://github.com/slimphp/Slim-Psr7/issues",
+ "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.1"
+ },
+ "install-path": "../slim/psr7"
+ },
+ {
+ "name": "stella-maris/clock",
+ "version": "0.1.7",
+ "version_normalized": "0.1.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/stella-maris-solutions/clock.git",
+ "reference": "fa23ce16019289a18bb3446fdecd45befcdd94f8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/stella-maris-solutions/clock/zipball/fa23ce16019289a18bb3446fdecd45befcdd94f8",
+ "reference": "fa23ce16019289a18bb3446fdecd45befcdd94f8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0|^8.0",
+ "psr/clock": "^1.0"
+ },
+ "time": "2022-11-25T16:15:06+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "StellaMaris\\Clock\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Andreas Heigl",
+ "role": "Maintainer"
+ }
+ ],
+ "description": "A pre-release of the proposed PSR-20 Clock-Interface",
+ "homepage": "https://gitlab.com/stella-maris/clock",
+ "keywords": [
+ "clock",
+ "datetime",
+ "point in time",
+ "psr20"
+ ],
+ "support": {
+ "source": "https://github.com/stella-maris-solutions/clock/tree/0.1.7"
+ },
+ "install-path": "../stella-maris/clock"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.32.0",
+ "version_normalized": "1.32.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "time": "2025-01-02T08:10:11+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/polyfill-php80"
+ }
+ ],
+ "dev": true,
+ "dev-package-names": []
+}
diff --git a/api_candidatos/vendor/composer/installed.php b/api_candidatos/vendor/composer/installed.php
new file mode 100644
index 0000000..3eeb821
--- /dev/null
+++ b/api_candidatos/vendor/composer/installed.php
@@ -0,0 +1,197 @@
+ array(
+ 'name' => '__root__',
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'reference' => '6bb919b212e576391c6c7e196f2955d79731b5ad',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev' => true,
+ ),
+ 'versions' => array(
+ '__root__' => array(
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'reference' => '6bb919b212e576391c6c7e196f2955d79731b5ad',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'defuse/php-encryption' => array(
+ 'pretty_version' => 'v2.4.0',
+ 'version' => '2.4.0.0',
+ 'reference' => 'f53396c2d34225064647a05ca76c1da9d99e5828',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../defuse/php-encryption',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'fig/http-message-util' => array(
+ 'pretty_version' => '1.1.5',
+ 'version' => '1.1.5.0',
+ 'reference' => '9d94dc0154230ac39e5bf89398b324a86f63f765',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../fig/http-message-util',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'lcobucci/clock' => array(
+ 'pretty_version' => '2.3.0',
+ 'version' => '2.3.0.0',
+ 'reference' => 'c7aadcd6fd97ed9e199114269c0be3f335e38876',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../lcobucci/clock',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'lcobucci/jwt' => array(
+ 'pretty_version' => '4.0.4',
+ 'version' => '4.0.4.0',
+ 'reference' => '55564265fddf810504110bd68ca311932324b0e9',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../lcobucci/jwt',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'league/event' => array(
+ 'pretty_version' => '2.3.0',
+ 'version' => '2.3.0.0',
+ 'reference' => '062ebb450efbe9a09bc2478e89b7c933875b0935',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../league/event',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'league/oauth2-server' => array(
+ 'pretty_version' => '8.4.3',
+ 'version' => '8.4.3.0',
+ 'reference' => '8a59a84450f0f64adcea8e1f8c0e0d9dfc8887d1',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../league/oauth2-server',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'league/oauth2server' => array(
+ 'dev_requirement' => false,
+ 'replaced' => array(
+ 0 => '*',
+ ),
+ ),
+ 'league/uri' => array(
+ 'pretty_version' => '6.8.0',
+ 'version' => '6.8.0.0',
+ 'reference' => 'a700b4656e4c54371b799ac61e300ab25a2d1d39',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../league/uri',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'league/uri-interfaces' => array(
+ 'pretty_version' => '2.3.0',
+ 'version' => '2.3.0.0',
+ 'reference' => '00e7e2943f76d8cb50c7dfdc2f6dee356e15e383',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../league/uri-interfaces',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'lncd/oauth2' => array(
+ 'dev_requirement' => false,
+ 'replaced' => array(
+ 0 => '*',
+ ),
+ ),
+ 'paragonie/random_compat' => array(
+ 'pretty_version' => 'v9.99.100',
+ 'version' => '9.99.100.0',
+ 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../paragonie/random_compat',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'psr/clock' => array(
+ 'pretty_version' => '1.0.0',
+ 'version' => '1.0.0.0',
+ 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/clock',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'psr/clock-implementation' => array(
+ 'dev_requirement' => false,
+ 'provided' => array(
+ 0 => '1.0',
+ ),
+ ),
+ 'psr/http-factory' => array(
+ 'pretty_version' => '1.1.0',
+ 'version' => '1.1.0.0',
+ 'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/http-factory',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'psr/http-factory-implementation' => array(
+ 'dev_requirement' => false,
+ 'provided' => array(
+ 0 => '^1.0',
+ ),
+ ),
+ 'psr/http-message' => array(
+ 'pretty_version' => '1.1',
+ 'version' => '1.1.0.0',
+ 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/http-message',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'psr/http-message-implementation' => array(
+ 'dev_requirement' => false,
+ 'provided' => array(
+ 0 => '^1.0 || ^2.0',
+ ),
+ ),
+ 'ralouphie/getallheaders' => array(
+ 'pretty_version' => '3.0.3',
+ 'version' => '3.0.3.0',
+ 'reference' => '120b605dfeb996808c31b6477290a714d356e822',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../ralouphie/getallheaders',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'slim/psr7' => array(
+ 'pretty_version' => '1.7.1',
+ 'version' => '1.7.1.0',
+ 'reference' => 'fe98653e7983010aa85c1d137c9b9ad5a1cd187d',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../slim/psr7',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'stella-maris/clock' => array(
+ 'pretty_version' => '0.1.7',
+ 'version' => '0.1.7.0',
+ 'reference' => 'fa23ce16019289a18bb3446fdecd45befcdd94f8',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../stella-maris/clock',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-php80' => array(
+ 'pretty_version' => 'v1.32.0',
+ 'version' => '1.32.0.0',
+ 'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-php80',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ ),
+);
diff --git a/api_candidatos/vendor/composer/platform_check.php b/api_candidatos/vendor/composer/platform_check.php
new file mode 100644
index 0000000..4c3a5d6
--- /dev/null
+++ b/api_candidatos/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+= 80100)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+ } elseif (!headers_sent()) {
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+ }
+ }
+ trigger_error(
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
+ E_USER_ERROR
+ );
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/LICENSE b/api_candidatos/vendor/defuse/php-encryption/LICENSE
new file mode 100644
index 0000000..aaf2fe9
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Taylor Hornby
+Copyright (c) 2016 Paragon Initiative Enterprises .
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/api_candidatos/vendor/defuse/php-encryption/README.md b/api_candidatos/vendor/defuse/php-encryption/README.md
new file mode 100644
index 0000000..1394d31
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/README.md
@@ -0,0 +1,121 @@
+php-encryption
+===============
+
+
+[](https://codecov.io/gh/defuse/php-encryption)
+[](https://packagist.org/packages/defuse/php-encryption)
+[](https://packagist.org/packages/defuse/php-encryption)
+[](https://packagist.org/packages/defuse/php-encryption)
+
+```terminal
+composer require defuse/php-encryption
+```
+
+This is a library for encrypting data with a key or password in PHP. **It
+requires PHP 5.6 or newer and OpenSSL 1.0.1 or newer.** We recommend using a
+version of PHP that [still has security
+support](https://www.php.net/supported-versions.php), which at the time of
+writing means PHP 8.0 or later. Using this library with an unsupported
+version of PHP could lead to security vulnerabilities.
+
+The current version of `php-encryption` is v2.4.0. This library is expected to
+remain stable and supported by its authors with security and bugfixes until at
+least January 1st, 2024.
+
+The library is a joint effort between [Taylor Hornby](https://defuse.ca/) and
+[Scott Arciszewski](https://paragonie.com/blog/author/scott-arcizewski) as well
+as numerous open-source contributors.
+
+What separates this library from other PHP encryption libraries is, firstly,
+that it is secure. The authors used to encounter insecure PHP encryption code on
+a daily basis, so they created this library to bring more security to the
+ecosystem. Secondly, this library is "difficult to misuse." Like
+[libsodium](https://github.com/jedisct1/libsodium), its API is designed to be
+easy to use in a secure way and hard to use in an insecure way.
+
+
+Dependencies
+------------
+
+This library requires no special dependencies except for PHP 5.6 or newer with
+the OpenSSL extensions (version 1.0.1 or later) enabled (this is the default).
+It uses [random\_compat](https://github.com/paragonie/random_compat), which is
+bundled in with this library so that your users will not need to follow any
+special installation steps.
+
+Getting Started
+----------------
+
+Start with the [**Tutorial**](docs/Tutorial.md). You can find instructions for
+obtaining this library's code securely in the [Installing and
+Verifying](docs/InstallingAndVerifying.md) documentation.
+
+After you've read the tutorial and got the code, refer to the formal
+documentation for each of the classes this library provides:
+
+- [Crypto](docs/classes/Crypto.md)
+- [File](docs/classes/File.md)
+- [Key](docs/classes/Key.md)
+- [KeyProtectedByPassword](docs/classes/KeyProtectedByPassword.md)
+
+If you encounter difficulties, see the [FAQ](docs/FAQ.md) answers. The fixes to
+the most commonly-reported problems are explained there.
+
+If you're a cryptographer and want to understand the nitty-gritty details of how
+this library works, look at the [Cryptography Details](docs/CryptoDetails.md)
+documentation.
+
+If you're interested in contributing to this library, see the [Internal
+Developer Documentation](docs/InternalDeveloperDocs.md).
+
+Other Language Support
+----------------------
+
+This library is intended for server-side PHP software that needs to encrypt data at rest.
+If you are building software that needs to encrypt client-side, or building a system that
+requires cross-platform encryption/decryption support, we strongly recommend using
+[libsodium](https://download.libsodium.org/doc/bindings_for_other_languages) instead.
+
+Examples
+---------
+
+If the documentation is not enough for you to understand how to use this
+library, then you can look at an example project that uses this library:
+
+- [encutil](https://github.com/defuse/encutil)
+- [fileencrypt](https://github.com/tsusanka/fileencrypt)
+
+Security Audit Status
+---------------------
+
+This code has not been subjected to a formal, paid, security audit. However, it
+has received lots of review from members of the PHP security community, and the
+authors are experienced with cryptography. In all likelihood, you are safer
+using this library than almost any other encryption library for PHP.
+
+If you use this library as a part of your business and would like to help fund
+a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm).
+
+Public Keys
+------------
+
+The GnuPG public key used to sign current and older releases is available in
+[dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is:
+
+```
+2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538
+```
+
+You can verify it against Taylor Hornby's [contact
+page](https://defuse.ca/contact.htm) and
+[twitter](https://twitter.com/DefuseSec/status/723741424253059074).
+
+Due to the old key expiring, new releases will be signed with a new public key
+available in [dist/signingkey-new.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc). Its fingerprint is:
+
+```
+6DD6 E677 0281 5846 FC85 25A3 DD2E 507F 7BDB 1669
+```
+
+A signature of this new key by the old key is available in
+[dist/signingkey-new.asc.sig](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc.sig).
diff --git a/api_candidatos/vendor/defuse/php-encryption/bin/generate-defuse-key b/api_candidatos/vendor/defuse/php-encryption/bin/generate-defuse-key
new file mode 100644
index 0000000..24e31b5
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/bin/generate-defuse-key
@@ -0,0 +1,14 @@
+#!/usr/bin/env php
+saveToAsciiSafeString(), "\n";
diff --git a/api_candidatos/vendor/defuse/php-encryption/composer.json b/api_candidatos/vendor/defuse/php-encryption/composer.json
new file mode 100644
index 0000000..29a1d52
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "defuse/php-encryption",
+ "description": "Secure PHP Encryption Library",
+ "license": "MIT",
+ "keywords": ["security", "encryption", "AES", "openssl", "cipher", "cryptography", "symmetric key cryptography", "crypto", "encrypt", "authenticated encryption"],
+ "authors": [
+ {
+ "name": "Taylor Hornby",
+ "email": "taylor@defuse.ca",
+ "homepage": "https://defuse.ca/"
+ },
+ {
+ "name": "Scott Arciszewski",
+ "email": "info@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Defuse\\Crypto\\": "src"
+ }
+ },
+ "require": {
+ "paragonie/random_compat": ">= 2",
+ "ext-openssl": "*",
+ "php": ">=5.6.0"
+ },
+ "require-dev": {
+ "yoast/phpunit-polyfills": "^2.0.0",
+ "phpunit/phpunit": "^5|^6|^7|^8|^9|^10"
+ },
+ "bin": [
+ "bin/generate-defuse-key"
+ ]
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/dist/Makefile b/api_candidatos/vendor/defuse/php-encryption/dist/Makefile
new file mode 100644
index 0000000..bffe616
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/dist/Makefile
@@ -0,0 +1,39 @@
+# This builds defuse-crypto.phar. To run this Makefile, `box` and `composer`
+# must be installed and in your $PATH. Run it from inside the dist/ directory.
+
+box := $(shell which box)
+composer := $(shell which composer)
+gitcommit := $(shell git rev-parse HEAD)
+
+.PHONY: all
+all: build-phar
+
+.PHONY: sign-phar
+sign-phar:
+ gpg -u DD2E507F7BDB1669 --armor --output defuse-crypto.phar.sig --detach-sig defuse-crypto.phar
+
+# ensure we run in clean tree. export git tree and run there.
+.PHONY: build-phar
+build-phar:
+ @echo "Creating .phar from revision $(shell git rev-parse HEAD)."
+ rm -rf worktree
+ install -d worktree
+ (cd $(CURDIR)/..; git archive HEAD) | tar -x -C worktree
+ $(MAKE) -f $(CURDIR)/Makefile -C worktree defuse-crypto.phar
+ mv worktree/*.phar .
+ rm -rf worktree
+
+.PHONY: clean
+clean:
+ rm -vf defuse-crypto.phar defuse-crypto.phar.sig
+
+# Inside workdir/:
+
+defuse-crypto.phar: dist/box.json composer.lock
+ cp dist/box.json .
+ php $(box) compile -c box.json -v
+
+composer.lock:
+ $(composer) config autoloader-suffix $(gitcommit)
+ $(composer) install --no-dev
+
diff --git a/api_candidatos/vendor/defuse/php-encryption/dist/box.json b/api_candidatos/vendor/defuse/php-encryption/dist/box.json
new file mode 100644
index 0000000..3c81e95
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/dist/box.json
@@ -0,0 +1,22 @@
+{
+ "chmod": "0755",
+ "finder": [
+ {
+ "in": "src",
+ "name": "*.php"
+ },
+ {
+ "in": "vendor/composer",
+ "name": "*.php"
+ },
+ {
+ "in": "vendor/paragonie",
+ "name": "*.php",
+ "exclude": "other"
+ }
+ ],
+ "main": "vendor/autoload.php",
+ "output": "defuse-crypto.phar",
+ "shebang": false,
+ "stub": true
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/dist/phar-testing-autoload.php b/api_candidatos/vendor/defuse/php-encryption/dist/phar-testing-autoload.php
new file mode 100644
index 0000000..433395a
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/dist/phar-testing-autoload.php
@@ -0,0 +1,4 @@
+
diff --git a/api_candidatos/vendor/defuse/php-encryption/dist/signingkey-new.asc b/api_candidatos/vendor/defuse/php-encryption/dist/signingkey-new.asc
new file mode 100644
index 0000000..7e3a4a1
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/dist/signingkey-new.asc
@@ -0,0 +1,53 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBF5V4TABEAC4G2BkHDaqbip3gj1oOqKh3V6LQa9QAd/f/hyhmR5hXpciPxf3
+NNHAxzoGAuB51f1YPJTNO59mGKHDuCFfr0pI94HDGoW4WgxqnUyqHBj2+/JhQPqO
+lgDT0QDcfxmUd0wfZl/Ur+8SsaBYvfFWNmPaXHp9m4MMRtw9uZNIW6LlZ24JqmGy
+/YUELUSH7P+uJ4HQEdixaqQ0VgIomRDI+5IwdJMtq4TSNazQm3nNmH9Em37cdi6J
+NDfFRy2QxJDmuqlg8mkpS5TvrrNy/UJwIeXO9PuGaBODr8GAKWvhkpfGlxN+hWMY
+01bOFnuEnOcuXw8BjPAKHqwOuGvinNmQ7lX1Rj3ssd31sTUimop0oNjOTZztpJBR
+m6wO2/YGMjt+eL02NgBBDIsV837PeWuJmymTJDGQuBjZ3JWUfyT3AnkA8OU5vKjs
+pM8AjIiuU7C8zQhUSHDnukTKWpBmMdOXeWNb5Ye6n60wJWzWFGlm+cYalPs+q3H8
+bxHxHEdFT0rUpxB05bc9zsZ3gGkc2NTNW/00a6gvTyX1UsBAeNgvVSHBHQGfow6o
+ZKG+LnVxd+cl97ay6kP29eLypXffbXQ3hMXe9tUNBjAeiok9tssU70Epr9wTh/Fm
+/iEbGc8VhS4TSk3c+3eS16rvlQ51FmAlmG6kAnN/ah+BiM4syPrWcJHIDQARAQAB
+tG1kZWZ1c2UvcGhwLWVuY3J5cHRpb24gbWFpbnRhaW5lcnMgKGRlZnVzZS9waHAt
+ZW5jcnlwdGlvbiByZWxlYXNlIHNpZ25pbmcga2V5KSA8cGhwLWVuY3J5cHRpb25A
+ZGVmdXNlLmludmFsaWQ+iQJUBBMBCAA+FiEEbdbmdwKBWEb8hSWj3S5Qf3vbFmkF
+Al5V4TACGwMFCQlmAYAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ3S5Qf3vb
+FmnQ4Q//bHAwDI7CcTlDDktdRCP0YCRtb5zMa6vSqnZLi5aTqzmL1yQCAp1/JTwf
+nlHn5xt60eKwfjIKj7Kj0n8WDFYnlOu30H5fNtFHis0xeS7GkH60tIE/pQUZILlB
+Wcnx/ZPnlxccjtfSbnpelSPdvIoHVRNhh1ZYG/49kuuv8TMbMIi2FBAzGEatPoLN
+f4wntoOKGvl8R2rPc2geapXTz++X+HJkddHCISR61obDRl9P0t9x+0M7gGSVMGfC
+GC4wh3JB6/ha8l+DI+l88/64IKRG+M33bBwLGQ0RIhotHIy442gLJTm6TeoH8iUz
+xCBwPYW+Ta1wZi17PIjHdTkNGBeEj/Hr5tTVV3oxrQVgHCymzasnz9IwcCCMwpKK
+ZOMFl0+PT3TSBKLnUByvOB64YOjxU7t+sRf53Biz3yKzto5VdHGW64OG2vGFy/Xz
+vI5RqU34wjtEHxWfz8y2GBnhD2TzEFCIIWPAX3TDG64NBSEBjhUraOmoVoaYJlP6
+rqxIQo4yhC+f5rnr2ZA48Hnrg0jEdVvN07FegoOnQQPpYBBkOrkTDWChn8oiXMfg
+9bjv19zDOBVXl9EU+P8AhwTHz/pBKmhb97N9nYp/pbmejA+I0Kw1vZo7gaMxL938
+oQkdtWT70ZzcpcZfeKVXoZa/ddAmuxzNknZA8ZnjQ9Qhv7aNX2O5Ag0EXlXhMAEQ
+AM8od4/85i7ZPmM6C1M4n4XcXeKsuZKHLvLLcRHFGkjVdXRSaxpbk2yDJiLnB9hX
+GSJG2gUCT+yrimjQ71bJ4q9K2+mkVHVjdtCrCtoOYEIpMLzsRtqyAWotcVmdv8Zv
+4IIjxfdxpTkj9gZmUfDIe6tbN2iBCAo1HArXq1qSdof3ui8SqdWeinkd7lZMesFm
+dGQaAcHbmEakO5mRzljme8IBs3UY9j/zxEG1JbsHx9ua7CVwJ7lxi2SgSW6nF9k5
+CX5zbrDqlqSJNtDs+KbjCbI2eK+qe4qZWHPiw4bNBn6EWf97/4Os8w7Vrrpyd2eO
+1JENwjlG6WG9mbJdIWWwakZ0CeH5LnJo6dV47KZbbbB6ncavaL+VpfbTCgdOGsCc
+GcYUVl90/v5pPm2owx4Dg9hSfcp8fesQuq4b79NAcjF7meu5wgNdvFlfuXony+UC
+W2wNi0mi9lzLD0n0j0GDzWyd3r7yXmPTL4LhrQu/pIcWIljKI3GUAQZqIYbGAO3G
+7hEFT8rDWg2vKRtMag4iy5FvZFqR+7TwWJAcWnHJBZ95F9NzeYIFhp9a3hxbKXqD
+xEnyGgzAszUycq29BApT4/4rDZQuXuOBd4lJp8tSzctLjvo7D3la+MWD6AlDkYT4
+bGKN9NfRCzYr2Zq3jOByAV3d5hGgyzdJlZSqXAGtbHHdABEBAAGJAjwEGAEIACYW
+IQRt1uZ3AoFYRvyFJaPdLlB/e9sWaQUCXlXhMAIbDAUJCWYBgAAKCRDdLlB/e9sW
+aSGfD/wPeq6lGu8ocHIkO74VPioJRKRXDVLsY02xKP64p0RHUGFTOqqB3A3UV0ue
+tkizoUdfF5xkgJ18gbxXo8lotBq+Ita5hoYAfqJnTnucAPGovREJ+X1HfdK4pJqW
+KNJElBz+fC4chqksiUAuH7IMImmy0/lA+LqZagzkQJU10MvmiFZ6kn+X5Mb4izRl
+vAHo16eI4psApdT8Bs7mwAjgCHxS9Re46uOElB4Bx3iFPd/PEwHWnfr8x9TJZYKW
+fsShG31+vfBRCfGtfKGxiAkp3EEM11lzbbfMcC3lai5iJQ/FmHgoIDeIG2Ebuk4w
+/PYakSrpvkEYoMP31pVHDhzopVeURS2lpvQJ4CvTP5CVQtKrbuygow6GF8N/drCE
+hdEx22pzW02ADS9fgzrlDztIOlOvC9a+epISIaEjfrc9dWhrw6chZEoWIil2MVQR
+Sj0jZ8w/H7P88oHTOcFVel73ZEPg9eRUkqMnIn3DWUuqLI2SX/AtVnhdYHWTiOkq
+knsGofWxUSu3RZR2ZElK9hjNKdVbGDzHGAYeJihieTKIOXpCf6Ix5B32tmFpfmBV
+Q9YP3JLsRTxIMbXsJImand/r6fSjdmTpk2PovYPtE1HTJKaVHeagQdsrWw5LaJv0
+ZWuwJm0y0WJXcAEjwOHhBs0nvq2CXuZi2ZTPtY+DbsSFWhaN7g==
+=Ysgx
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/api_candidatos/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig b/api_candidatos/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig
new file mode 100644
index 0000000..56e1f3a
Binary files /dev/null and b/api_candidatos/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig differ
diff --git a/api_candidatos/vendor/defuse/php-encryption/dist/signingkey.asc b/api_candidatos/vendor/defuse/php-encryption/dist/signingkey.asc
new file mode 100644
index 0000000..63b6aa3
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/dist/signingkey.asc
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mQINBFarvO4BEACdQBaLt6SUBx1cB5liUu1qo+YwVLh9bxTregQtmEREMdTVqXYt
+e5b79uL4pQp2GlKHcEyRURS+6rIIruM0oh9ZYGTJYPAkCDzJxaU2awZeFbfBvpCm
+iF66/O4ZJI4mlT8dFKmxBJxDhfeOR2UmmhDiEsJK9FxBKUzvo/dWrX2pBzf8Y122
+iIaVraSo+tymaf7vriaIf/NnSKhDw8dtQYGM4NMrxxsPTfbCF8XiboDgTkoD2A+6
+NpOJYxA4Veedsf2TP9YLhljH4m5yYlfjjqBzbBCPWuE6Hhy5Xze9mncgDr7LKenm
+Ctf2NxW6y4O3RCI+9eLlBfFWB+KuGV87/b5daetX7NNLbjID8z2rqEa+d6wu5xA5
+Ta2uiVkAOEovr3XnkayZ9zth+Za7w7Ai0ln0N/LVMkM+Gu4z/pJv6HjmTGDM2wJb
+fs+UOM0TFdg+N81Do67XT2M4o0MeHyUqsIiWpYa2Qf1PNmqTQNJnRk8uZZ9I96Nh
+eCgNuCbhsQiYBMicox+xmuWAlGAfA06y0kCtmqGhiBGArdJlWvUqPqGiZ4Hln9z0
+FJmXDOh0Q/FIPxcDg8mKRRbx+lOP389PLsPpj4b2B/4PEgfpCCOwuKpLotATZxC1
+9JwFk0Y/cvUUkq4a+nAJBNtBbtRJkEesuuUnRq6XexmnE3uUucDcV0XCSwARAQAB
+tCBUYXlsb3IgSG9ybmJ5IDx0YXlsb3JAZGVmdXNlLmNhPokCPQQTAQgAJwUCVqu8
+7gIbAwUJB4TOAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA4XuBVoSkVOJbx
+EACG0F9blPMAsK05EWyNnnS4mw25zPfbaqqEvYbquAeM0nBpRDm7sRn2MNR0AL4g
+7XrtxE/4qYkdEl6f2wFCQeRhZgxE3w22llredzLme11Hic8hn4i7ysdIw0r9dMMR
+kjgR5UcWpv8iU847czyK09PkKW2EaLRbX2qbA7rNU5qCFKeD4Sy4bBTteISeVsHo
+Vr9o1/bRrMhgZ++ts8hYf0LmujIf5cxp+qcdKwCXSnS/gmmXaKRMCPv/Wdlq9bt6
+LX9jZB9lXBdGxcBJeFOsTG+QRDiVjg3d6i3o3TAKV87ALBI4v2ADEYtN8lviHo3/
+SovVKv6zrUsZHxhoGiLTiksNrYsKMmiMxdJCoOazmtUPnZ4UOtT8NdqMPoKvdoRz
+f4rhZ+f5jSVD9OuX2PDmfyq21Rdiym7Vcgr+uTIFJ3ShRHjWb/ytCwoB2FeGY6+G
+AKY58bTQvUIqEJvSov/+TAqZ4BfOuSdTLcHglV1OdUu2SFZvU2gmyVp0l5elGv5t
+FyUlBJUkQT9MtvsdLOR7vQi8QapV+9LWpqwvaj9hyEJz848DQ2sdYTphUytFHv7H
+k58DAtVhTrVjHyeefjiYtMl6vSAgTjy5LWAUpo5TfhdGrAi0Tdd/GD7amHoWoDy8
+EKXKq2xPLo3JOdkWYQUi5NErzEskfsSzpCOgyDJmGetWK7kCDQRWq7zuARAAu7/i
+cm8cjgLhHEX/bgfwOT2hLOLSjjve0O8YFSuJO9XqIHXqmfVOrqWtfG0Mh4bwlfqc
+MAvBfF5NSSPfAE4ftBAQ1e5jEv8hJeqICpq3IHTFX4etBs49NfNkyveQl/amVTu1
++/O5J4CuIcsEf3y0Xuu38n7EB3SfMQCWLcOR1NyZoX3bI+CGRpOVVoFse3ljSWL4
+LhLVl0WiEMXULsussEoN+c6x9KCyAi/jFOrxrTrFC//sZesKj6KucoqKGfwMWrrv
+IeRT9Ga8Wn5MJnQu0aWg+zVVYqTedXZLNLODgQIInFnXO0seBXy15yDok1y5bkx2
+sinKg4+mueYaGUpoUti0hM3J3yaC34i6Cwa8MQoLNw1JIS/oNtKjpMxyV10w8aoc
+PHRK3n7UYp10mJHx7aM+lldSKvVS1NTQmI4vloNLwMp324H5ANDFAlRUz7mysVnu
+DEEvigPSPxs5ZYENu/i7pCQC5qHfhrlBrQwTjhegr0pQPcumy2fO5SGC9l/5B7ev
+bqQSZmDeWWoTvh2w2wl5/RWAsgZKx6rDtkCqYx7sSBY17uorrxP24LP4zhq7NxRV
+nfdsLogbCFNVQ66u7qvq5zFccdFtg9h1HQWdS7wbnKSBGZoo5gl6js7GGtxfGbb0
+oQ9kp6eciF4U92r6POhVgbRe4CfPo50nqgZBddkAEQEAAYkCJQQYAQgADwUCVqu8
+7gIbDAUJB4TOAAAKCRA4XuBVoSkVOFJ8D/9J8IJ4XWUU3FYIaHJ3XeSoxDmTi7d5
+WmNdf1lmwz82MQjG4uw17oCbvQzmj4/a/CM1Ly4v0WwBhUf9aiNErD0ByHASFnuc
+tlQBLVJdk0vRyD0fZakGg64qCA76hiySjMhlGHkQFyP2mDORc2GNu/OqFGm79pXT
+ZUplXxd431E603/agM5xJrweutMMpP1nBFTSEMJvbMNzDVN8I1A1CH4zVmAVxOUk
+sQ5L5rXW+KeXWyiMF24+l2CMnkQ2CxfHpkcpfPJs1Cbt+TIBSSofIqK8QJXrb/2f
+Zpl/ftqW7Xe86rJFrB/Y/77LDWx10rqWEvfCqrBxrMj7ONAQfbKQF/IjAwDN17Wf
+1K74rqKnRu+KHCyNM89s1iDbQC9kzZfzYt4AEOvAH/ZQDMZffzPSbnfkBerExFpa
+93XMuiR66jiBsf9IXIQeydpJD4Ogl2sSUSxFEJxJ/bBSxPxC5w7/BVMA7Am1y8Zo
+3hrpqnX2PBzxG7L0FZ6fYkfR3p8JS7vI6nByBf2IDv8W32wn43olPf+u6uobHLvt
+ttapOjwPAhPDalRuxs9U6WSg06QJkT/0F8TFUPWpsFmKTl+G4Ty7PHWsjeeNHJCL
+7/5RQboFY3k8Jy3/sIofABO6Un9LJivDuu9PxqA0IgvaS6Mja8JdCCk9Nyk4vHB7
+IEgAL/CYqrk38w==
+=lmD7
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/api_candidatos/vendor/defuse/php-encryption/docs/CryptoDetails.md b/api_candidatos/vendor/defuse/php-encryption/docs/CryptoDetails.md
new file mode 100644
index 0000000..43abd72
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/docs/CryptoDetails.md
@@ -0,0 +1,64 @@
+Cryptography Details
+=====================
+
+Here is a high-level description of how this library works. Any discrepancy
+between this documentation and the actual implementation will be considered
+a security bug.
+
+Let's start with the following definitions:
+
+- HKDF-SHA256(*k*, *n*, *info*, *s*) is the key derivation function specified in
+ RFC 5869 (using the SHA256 hash function). The parameters are:
+ - *k*: The initial keying material.
+ - *n*: The number of output bytes.
+ - *info*: The info string.
+ - *s*: The salt.
+- AES-256-CTR(*m*, *k*, *iv*) is AES-256 encryption in CTR mode. The parameters
+ are:
+ - *m*: An arbitrary-length (possibly zero-length) message.
+ - *k*: A 32-byte key.
+ - *iv*: A 16-byte initialization vector (nonce).
+- PBKDF2-SHA256(*p*, *s*, *i*, *n*) is the password-based key derivation
+ function defined in RFC 2898 (using the SHA256 hash function). The parameters
+ are:
+ - *p*: The password string.
+ - *s*: The salt string.
+ - *i*: The iteration count.
+ - *n*: The output length in bytes.
+- VERSION is the string `"\xDE\xF5\x02\x00"`.
+- AUTHINFO is the string `"DefusePHP|V2|KeyForAuthentication"`.
+- ENCRINFO is the string `"DefusePHP|V2|KeyForEncryption"`.
+
+To encrypt a message *m* using a 32-byte key *k*, the following steps are taken:
+
+1. Generate a random 32-byte string *salt*.
+2. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*).
+3. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*).
+4. Generate a random 16-byte initialization vector *iv*.
+5. Compute *c* = AES-256-CTR(*m*, *ekey*, *iv*).
+6. Combine *ctxt* = VERSION || *salt* || *iv* || *c*.
+7. Compute *h* = HMAC-SHA256(*ctxt*, *akey*).
+8. Output *ctxt* || *h*.
+
+Decryption is roughly the reverse process (see the code for details, since the
+security of the decryption routine is highly implementation-dependent).
+
+For encryption using a password *p*, steps 1-3 above are replaced by:
+
+1. Generate a random 32-byte string *salt*.
+2. Compute *k* = PBKDF2-SHA256(SHA256(*p*), *salt*, 100000, 32).
+3. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*)
+4. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*)
+
+The remainder of the process is the same. Notice the reuse of the same *salt*
+for PBKDF2-SHA256 and HKDF-SHA256. The prehashing of the password in step 2 is
+done to prevent a [DoS attack using long
+passwords](https://github.com/defuse/php-encryption/issues/230).
+
+For `KeyProtectedByPassword`, the serialized key is encrypted according to the
+password encryption defined above. However, the actual password used for
+encryption is the SHA256 hash of the password the user provided. This is done in
+order to provide domain separation between the message encryption in the user's
+application and the internal key encryption done by this library. It fixes
+a [key replacement chosen-protocol
+attack](https://github.com/defuse/php-encryption/issues/240).
diff --git a/api_candidatos/vendor/defuse/php-encryption/docs/FAQ.md b/api_candidatos/vendor/defuse/php-encryption/docs/FAQ.md
new file mode 100644
index 0000000..9f77392
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/docs/FAQ.md
@@ -0,0 +1,51 @@
+Frequently Asked Questions
+===========================
+
+How do I use this library to encrypt passwords?
+------------------------------------------------
+
+Passwords should not be encrypted, they should be hashed with a *slow* password
+hashing function that's designed to slow down password guessing attacks. See
+[How to Safely Store Your Users' Passwords in
+2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016).
+
+How do I give it the same key every time instead of a new random key?
+----------------------------------------------------------------------
+
+A `Key` object can be saved to a string by calling its `saveToAsciiSafeString()`
+method. You will have to save that string somewhere safe, and then load it back
+into a `Key` object using `Key`'s `loadFromAsciiSafeString` static method.
+
+Where you store the string depends on your application. For example if you are
+using `KeyProtectedByPassword` to encrypt files with a user's login password,
+then you should not store the `Key` at all. If you are protecting sensitive data
+on a server that may be compromised, then you should store it in a hardware
+security module. When in doubt, consult a security expert.
+
+Why is an EnvironmentIsBrokenException getting thrown?
+-------------------------------------------------------
+
+Either you've encountered a bug in this library, or your system doesn't support
+the use of this library. For example, if your system does not have a secure
+random number generator, this library will refuse to run, by throwing that
+exception, instead of falling back to an insecure random number generator.
+
+Why am I getting a BadFormatException when loading a Key from a string?
+------------------------------------------------------------------------
+
+If you're getting this exception, then the string you're giving to
+`loadFromAsciiSafeString()` is *not* the same as the string you got from
+`saveToAsciiSafeString()`. Perhaps your database column isn't wide enough and
+it's truncating the string as you insert it?
+
+Does encrypting hide the length of the plaintext?
+--------------------------------------------------
+
+Encryption does not, and is not intended to, hide the length of the data being
+encrypted. For example, it is not safe to encrypt a field in which only a small
+number of different-length values are possible (e.g. "male" or "female") since
+it would be possible to tell what the plaintext is by looking at the length of
+the ciphertext. In order to do this safely, it is your responsibility to, before
+encrypting, pad the data out to the length of the longest string that will ever
+be encrypted. This way, all plaintexts are the same length, and no information
+about the plaintext can be gleaned from the length of the ciphertext.
diff --git a/api_candidatos/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md b/api_candidatos/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md
new file mode 100644
index 0000000..12b5fee
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md
@@ -0,0 +1,53 @@
+Getting The Code
+=================
+
+There are two ways to use this library in your applications. You can either:
+
+1. Use [Composer](https://getcomposer.org/), or
+2. `require_once` a single `.phar` file in your application.
+
+If you are not using either option (for example, because you're using Git submodules), you may need to write your own autoloader ([example](https://gist.github.com/paragonie-scott/949daee819bb7f19c50e5e103170b400)).
+
+Option 1: Using Composer
+-------------------------
+
+Run this inside the directory of your composer-enabled project:
+
+```sh
+composer require defuse/php-encryption
+```
+
+Unfortunately, composer doesn't provide a way for you to verify that the code
+you're getting was signed by this library's authors. If you want a more secure
+option, use the `.phar` method described below.
+
+Option 2: Including a PHAR
+----------------------------
+
+The `.phar` option lets you include this library into your project simply by
+calling `require_once` on a single file. Download `defuse-crypto.phar` and
+`defuse-crypto.phar.sig` from this project's
+[releases](https://github.com/defuse/php-encryption/releases) page.
+
+You should verify the integrity of the `.phar`. The `defuse-crypto.phar.sig`
+contains the signature of `defuse-crypto.phar`. It is signed with Taylor
+Hornby's PGP key. You can find Taylor's public key in `dist/signingkey.asc`. You
+can verify the public key's fingerprint against the Taylor Hornby's [contact
+page](https://defuse.ca/contact.htm) and
+[twitter](https://twitter.com/DefuseSec/status/723741424253059074).
+
+Once you have verified the signature, it is safe to use the `.phar`. Place it
+somewhere in your file system, e.g. `/var/www/lib/defuse-crypto.phar`, and then
+pass that path to `require_once`.
+
+```php
+ Whenever there is a conflict between security and some other property,
+ > security will be favored. For example, the library has runtime tests,
+ > which make it slower, but will hopefully stop it from encrypting stuff
+ > if the platform it's running on is broken.
+
+- Rule #2: It should be difficult to misuse the library.
+
+ > We assume the developers using this library have no experience with
+ > cryptography. We only assume that they know that the "key" is something
+ > you need to encrypt and decrypt the messages, and that it must be kept
+ > secret. Whenever possible, the library should refuse to encrypt or decrypt
+ > messages when it is not being used correctly.
+
+- Rule #3: The library aims only to be compatible with itself.
+
+ > Other PHP encryption libraries try to support every possible type of
+ > encryption, even the insecure ones (e.g. ECB mode). Because there are so
+ > many options, inexperienced developers must decide whether to use "CBC
+ > mode" or "ECB mode" when both are meaningless terms to them. This
+ > inevitably leads to vulnerabilities.
+
+ > This library will only support one secure mode. A developer using this
+ > library will call "encrypt" and "decrypt" methods without worrying about
+ > how they are implemented.
+
+- Rule #4: The library should require no special installation.
+
+ > Some PHP encryption libraries, like libsodium-php, are not straightforward
+ > to install and cannot packaged with "just download and extract"
+ > applications. This library will always be just a handful of PHP files that
+ > you can copy to your source tree and require().
+
+Publishing Releases
+--------------------
+
+To make a release, you will need to install [composer](https://getcomposer.org/)
+and [box](https://github.com/box-project/box2) on your system. They will need to
+be available in your `$PATH` so that running the commands `composer` and `box`
+in your terminal run them, respectively. You will also need the private key for
+signing (ID: 7B4B2D98) available.
+
+Once you have those tools installed and the key available follow these steps:
+
+**Remember to set the version number in `composer.json`!**
+
+Make a fresh clone of the repository:
+
+```
+git clone
+```
+
+Check out the branch you want to release:
+
+```
+git checkout
+```
+
+Check that the version number in composer.json is correct (or not specified so that it gets picked up from the git tag):
+
+```
+cat composer.json
+```
+
+Check that the version number and support lifetime in README.md are correct:
+
+```
+cat README.md
+```
+
+Run the tests:
+
+```
+composer install
+./test.sh
+```
+
+Generate the `.phar`:
+
+```
+cd dist
+make build-phar
+```
+
+Test the `.phar`:
+
+```
+cd ../
+./test.sh dist/phar-testing-autoload.php
+```
+
+Sign the `.phar`:
+
+```
+cd dist
+make sign-phar
+```
+
+Tag the release:
+
+```
+git -c user.signingkey=DD2E507F7BDB1669 tag -s "" -m ""
+```
+
+`` should be in the format `v2.0.0` and `` should look
+like "Release of v2.0.0."
+
+Push the tag to github, then use the
+[releases](https://github.com/defuse/php-encryption/releases) page to draft
+a new release for that tag. Upload the `.phar` and the `.phar.sig` file to be
+included as part of that release.
diff --git a/api_candidatos/vendor/defuse/php-encryption/docs/Tutorial.md b/api_candidatos/vendor/defuse/php-encryption/docs/Tutorial.md
new file mode 100644
index 0000000..a40cac3
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/docs/Tutorial.md
@@ -0,0 +1,314 @@
+Tutorial
+=========
+
+Hello! If you're reading this file, it's because you want to add encryption to
+one of your PHP projects. My job, as the person writing this documentation, is
+to help you make sure you're doing the right thing and then show you how to use
+this library to do it. To help me help you, please read the documentation
+*carefully* and *deliberately*.
+
+A Word of Caution
+------------------
+
+Encryption is not magic dust you can sprinkle on a system to make it more
+secure. The way encryption is integrated into a system's design needs to be
+carefully thought out. Sometimes, encryption is the wrong thing to use. Other
+times, encryption needs to be used in a very specific way in order for it to
+work as intended. Even if you are sure of what you are doing, we strongly
+recommend seeking advice from an expert.
+
+The first step is to think about your application's threat model. Ask yourself
+the following questions. Who will want to attack my application, and what will
+they get out of it? Are they trying to steal some information? Trying to alter
+or destroy some information? Or just trying to make the system go down so people
+can't access it? Then ask yourself how encryption can help combat those threats.
+If you're going to add encryption to your application, you should have a very
+clear idea of exactly which kinds of attacks it's helping to secure your
+application against. Once you have your threat model, think about what kinds of
+attacks it *does not* cover, and whether or not you should improve your threat
+model to include those attacks.
+
+**This isn't for storing user login passwords:** The most common use of
+cryptography in web applications is to protect the users' login passwords. If
+you're trying to use this library to "encrypt" your users' passwords, you're in
+the wrong place. Passwords shouldn't be *encrypted*, they should be *hashed*
+with a slow computation-heavy function that makes password guessing attacks more
+expensive. See [How to Safely Store Your Users' Passwords in
+2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016).
+
+**This isn't for encrypting network communication:** Likewise, if you're trying
+to encrypt messages sent between two parties over the Internet, you don't want
+to be using this library. For that, set up a TLS connection between the two
+points, or, if it's a chat app, use the [Signal
+Protocol](https://whispersystems.org/blog/advanced-ratcheting/).
+
+What this library provides is symmetric encryption for "data at rest." This
+means it is not suitable for use in building protocols where "data is in motion"
+(i.e. moving over a network) except in limited set of cases.
+
+Please note that **encryption does not, and is not intended to, hide the
+*length* of the data being encrypted.** For example, it is not safe to encrypt
+a field in which only a small number of different-length values are possible
+(e.g. "male" or "female") since it would be possible to tell what the plaintext
+is by looking at the length of the ciphertext. In order to do this safely, it is
+your responsibility to, before encrypting, pad the data out to the length of the
+longest string that will ever be encrypted. This way, all plaintexts are the
+same length, and no information about the plaintext can be gleaned from the
+length of the ciphertext.
+
+Getting the Code
+-----------------
+
+There are several different ways to obtain this library's code and to add it to
+your project. Even if you've already cloned the code from GitHub, you should
+take steps to verify the cryptographic signatures to make sure the code you got
+was not intercepted and modified by an attacker.
+
+Please head over to the [**Installing and
+Verifying**](InstallingAndVerifying.md) documentation to get the code, and then
+come back here to continue the tutorial.
+
+Using the Library
+------------------
+
+I'm going to assume you know what symmetric encryption is, and the difference
+between symmetric and asymmetric encryption. If you don't, I recommend taking
+[Dan Boneh's Cryptography I course](https://www.coursera.org/learn/crypto/) on
+Coursera.
+
+To give you a quick introduction to the library, I'm going to explain how it
+would be used in two sterotypical scenarios. Hopefully, one of these sterotypes
+is close enough to what you want to do that you'll be able to figure out what
+needs to be different on your own.
+
+### Formal Documentation
+
+While this tutorial should get you up and running fast, it's important to
+understand how this library behaves. Please make sure to read the formal
+documentation of all of the functions you're using, since there are some
+important security warnings there.
+
+The following classes are available for you to use:
+
+- [Crypto](classes/Crypto.md): Encrypting and decrypting strings.
+- [File](classes/File.md): Encrypting and decrypting files.
+- [Key](classes/Key.md): Represents a secret encryption key.
+- [KeyProtectedByPassword](classes/KeyProtectedByPassword.md): Represents
+ a secret encryption key that needs to be "unlocked" by a password before it
+ can be used.
+
+### Scenario #1: Keep data secret from the database administrator
+
+In this scenario, our threat model is as follows. Alice is a server
+administrator responsible for managing a trusted web server. Eve is a database
+administrator responsible for managing a database server. Dave is a web
+developer working on code that will eventually run on the trusted web server.
+
+Let's say Alice and Dave trust each other, and Alice is going to host Dave's
+application on her server. But both Alice and Dave don't trust Eve. They know
+Eve is a good database administrator, but she might have incentive to steal the
+data from the database. They want to keep some of the web application's data
+secret from Eve.
+
+In order to do that, Alice will use the included `generate-defuse-key` script
+which generates a random encryption key and prints it to standard output:
+
+```sh
+$ composer require defuse/php-encryption
+$ vendor/bin/generate-defuse-key
+```
+
+Alice will run this script once and save the output to a configuration file, say
+in `/etc/daveapp-secret-key.txt` and set the file permissions so that only the
+user that the website PHP scripts run as can access it.
+
+Dave will write his code to load the key from the configuration file:
+
+```php
+saveToAsciiSafeString();
+ // ... save $protected_key_encoded into the user's account record
+}
+```
+
+**WARNING:** Because of the way `KeyProtectedByPassword` is implemented, knowing
+`SHA256($password)` is enough to decrypt a `KeyProtectedByPassword`. To be
+secure, your application MUST NOT EVER compute `SHA256($password)` and use or
+store it for any reason. You must also make sure that other libraries your
+application is using don't compute it either.
+
+Then, when the user logs in, Dave's code will load the protected key from the
+user's account record, unlock it to get a `Key` object, and save the `Key`
+object somewhere safe (like temporary memory-backed session storage or
+a cookie). Note that wherever Dave's code saves the key, it must be destroyed
+once the user logs out, or else the attacker might be able to find users' keys
+even if they were never logged in during the attack.
+
+```php
+unlockKey($password);
+$user_key_encoded = $user_key->saveToAsciiSafeString();
+// ... save $user_key_encoded in a cookie
+```
+
+```php
+ 0,
+ 'Trying to increment a nonce by a nonpositive amount'
+ );
+
+ Core::ensureTrue(
+ $inc <= PHP_INT_MAX - 255,
+ 'Integer overflow may occur'
+ );
+
+ /*
+ * We start at the rightmost byte (big-endian)
+ * So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584
+ */
+ for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) {
+ $sum = \ord($ctr[$i]) + $inc;
+
+ /* Detect integer overflow and fail. */
+ Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment');
+
+ $ctr[$i] = \pack('C', $sum & 0xFF);
+ $inc = $sum >> 8;
+ }
+ return $ctr;
+ }
+
+ /**
+ * Returns a random byte string of the specified length.
+ *
+ * @param int $octets
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string
+ */
+ public static function secureRandom($octets)
+ {
+ if ($octets <= 0) {
+ throw new Ex\CryptoException(
+ 'A zero or negative amount of random bytes was requested.'
+ );
+ }
+ self::ensureFunctionExists('random_bytes');
+ try {
+ return \random_bytes(max(1, $octets));
+ } catch (\Exception $ex) {
+ throw new Ex\EnvironmentIsBrokenException(
+ 'Your system does not have a secure random number generator.'
+ );
+ }
+ }
+
+ /**
+ * Computes the HKDF key derivation function specified in
+ * http://tools.ietf.org/html/rfc5869.
+ *
+ * @param string $hash Hash Function
+ * @param string $ikm Initial Keying Material
+ * @param int $length How many bytes?
+ * @param string $info What sort of key are we deriving?
+ * @param string $salt
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @psalm-suppress UndefinedFunction - We're checking if the function exists first.
+ *
+ * @return string
+ */
+ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
+ {
+ static $nativeHKDF = null;
+ if ($nativeHKDF === null) {
+ $nativeHKDF = \is_callable('\\hash_hkdf');
+ }
+ if ($nativeHKDF) {
+ if (\is_null($salt)) {
+ $salt = '';
+ }
+ return \hash_hkdf($hash, $ikm, $length, $info, $salt);
+ }
+
+ $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true));
+
+ // Sanity-check the desired output length.
+ Core::ensureTrue(
+ !empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length,
+ 'Bad output length requested of HDKF.'
+ );
+
+ // "if [salt] not provided, is set to a string of HashLen zeroes."
+ if (\is_null($salt)) {
+ $salt = \str_repeat("\x00", $digest_length);
+ }
+
+ // HKDF-Extract:
+ // PRK = HMAC-Hash(salt, IKM)
+ // The salt is the HMAC key.
+ $prk = \hash_hmac($hash, $ikm, $salt, true);
+
+ // HKDF-Expand:
+
+ // This check is useless, but it serves as a reminder to the spec.
+ Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length);
+
+ // T(0) = ''
+ $t = '';
+ $last_block = '';
+ for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) {
+ // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??)
+ $last_block = \hash_hmac(
+ $hash,
+ $last_block . $info . \chr($block_index),
+ $prk,
+ true
+ );
+ // T = T(1) | T(2) | T(3) | ... | T(N)
+ $t .= $last_block;
+ }
+
+ // ORM = first L octets of T
+ /** @var string $orm */
+ $orm = Core::ourSubstr($t, 0, $length);
+ Core::ensureTrue(\is_string($orm));
+ return $orm;
+ }
+
+ /**
+ * Checks if two equal-length strings are the same without leaking
+ * information through side channels.
+ *
+ * @param string $expected
+ * @param string $given
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return bool
+ */
+ public static function hashEquals($expected, $given)
+ {
+ static $native = null;
+ if ($native === null) {
+ $native = \function_exists('hash_equals');
+ }
+ if ($native) {
+ return \hash_equals($expected, $given);
+ }
+
+ // We can't just compare the strings with '==', since it would make
+ // timing attacks possible. We could use the XOR-OR constant-time
+ // comparison algorithm, but that may not be a reliable defense in an
+ // interpreted language. So we use the approach of HMACing both strings
+ // with a random key and comparing the HMACs.
+
+ // We're not attempting to make variable-length string comparison
+ // secure, as that's very difficult. Make sure the strings are the same
+ // length.
+ Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given));
+
+ $blind = Core::secureRandom(32);
+ $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind);
+ $correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind);
+ return $correct_compare === $message_compare;
+ }
+ /**
+ * Throws an exception if the constant doesn't exist.
+ *
+ * @param string $name
+ * @return void
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ */
+ public static function ensureConstantExists($name)
+ {
+ Core::ensureTrue(
+ \defined($name),
+ 'Constant '.$name.' does not exists'
+ );
+ }
+
+ /**
+ * Throws an exception if the function doesn't exist.
+ *
+ * @param string $name
+ * @return void
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ */
+ public static function ensureFunctionExists($name)
+ {
+ Core::ensureTrue(
+ \function_exists($name),
+ 'function '.$name.' does not exists'
+ );
+ }
+
+ /**
+ * Throws an exception if the condition is false.
+ *
+ * @param bool $condition
+ * @param string $message
+ * @return void
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ */
+ public static function ensureTrue($condition, $message = '')
+ {
+ if (!$condition) {
+ throw new Ex\EnvironmentIsBrokenException($message);
+ }
+ }
+
+ /*
+ * We need these strlen() and substr() functions because when
+ * 'mbstring.func_overload' is set in php.ini, the standard strlen() and
+ * substr() are replaced by mb_strlen() and mb_substr().
+ */
+
+ /**
+ * Computes the length of a string in bytes.
+ *
+ * @param string $str
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return int
+ */
+ public static function ourStrlen($str)
+ {
+ static $exists = null;
+ if ($exists === null) {
+ $exists = \extension_loaded('mbstring') && \function_exists('mb_strlen');
+ }
+ if ($exists) {
+ $length = \mb_strlen($str, '8bit');
+ Core::ensureTrue($length !== false);
+ return $length;
+ } else {
+ return \strlen($str);
+ }
+ }
+
+ /**
+ * Behaves roughly like the function substr() in PHP 7 does.
+ *
+ * @param string $str
+ * @param int $start
+ * @param int $length
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string|bool
+ */
+ public static function ourSubstr($str, $start, $length = null)
+ {
+ static $exists = null;
+ if ($exists === null) {
+ $exists = \extension_loaded('mbstring') && \function_exists('mb_substr');
+ }
+
+ // This is required to make mb_substr behavior identical to substr.
+ // Without this, mb_substr() would return false, contra to what the
+ // PHP documentation says (it doesn't say it can return false.)
+ $input_len = Core::ourStrlen($str);
+ if ($start === $input_len && !$length) {
+ return '';
+ }
+
+ if ($start > $input_len) {
+ return false;
+ }
+
+ // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 5.3,
+ // so we have to find the length ourselves. Also, substr() doesn't
+ // accept null for the length.
+ if (! isset($length)) {
+ if ($start >= 0) {
+ $length = $input_len - $start;
+ } else {
+ $length = -$start;
+ }
+ }
+
+ if ($length < 0) {
+ throw new \InvalidArgumentException(
+ "Negative lengths are not supported with ourSubstr."
+ );
+ }
+
+ if ($exists) {
+ $substr = \mb_substr($str, $start, $length, '8bit');
+ // At this point there are two cases where mb_substr can
+ // legitimately return an empty string. Either $length is 0, or
+ // $start is equal to the length of the string (both mb_substr and
+ // substr return an empty string when this happens). It should never
+ // ever return a string that's longer than $length.
+ if (Core::ourStrlen($substr) > $length || (Core::ourStrlen($substr) === 0 && $length !== 0 && $start !== $input_len)) {
+ throw new Ex\EnvironmentIsBrokenException(
+ 'Your version of PHP has bug #66797. Its implementation of
+ mb_substr() is incorrect. See the details here:
+ https://bugs.php.net/bug.php?id=66797'
+ );
+ }
+ return $substr;
+ }
+
+ return \substr($str, $start, $length);
+ }
+
+ /**
+ * Computes the PBKDF2 password-based key derivation function.
+ *
+ * The PBKDF2 function is defined in RFC 2898. Test vectors can be found in
+ * RFC 6070. This implementation of PBKDF2 was originally created by Taylor
+ * Hornby, with improvements from http://www.variations-of-shadow.com/.
+ *
+ * @param string $algorithm The hash algorithm to use. Recommended: SHA256
+ * @param string $password The password.
+ * @param string $salt A salt that is unique to the password.
+ * @param int $count Iteration count. Higher is better, but slower. Recommended: At least 1000.
+ * @param int $key_length The length of the derived key in bytes.
+ * @param bool $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string A $key_length-byte key derived from the password and salt.
+ */
+ public static function pbkdf2(
+ $algorithm,
+ #[\SensitiveParameter]
+ $password,
+ $salt,
+ $count,
+ $key_length,
+ $raw_output = false
+ )
+ {
+ // Type checks:
+ if (! \is_string($algorithm)) {
+ throw new \InvalidArgumentException(
+ 'pbkdf2(): algorithm must be a string'
+ );
+ }
+ if (! \is_string($password)) {
+ throw new \InvalidArgumentException(
+ 'pbkdf2(): password must be a string'
+ );
+ }
+ if (! \is_string($salt)) {
+ throw new \InvalidArgumentException(
+ 'pbkdf2(): salt must be a string'
+ );
+ }
+ // Coerce strings to integers with no information loss or overflow
+ $count += 0;
+ $key_length += 0;
+
+ $algorithm = \strtolower($algorithm);
+ Core::ensureTrue(
+ \in_array($algorithm, \hash_algos(), true),
+ 'Invalid or unsupported hash algorithm.'
+ );
+
+ // Whitelist, or we could end up with people using CRC32.
+ $ok_algorithms = [
+ 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
+ 'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool',
+ ];
+ Core::ensureTrue(
+ \in_array($algorithm, $ok_algorithms, true),
+ 'Algorithm is not a secure cryptographic hash function.'
+ );
+
+ Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.');
+
+ if (\function_exists('hash_pbkdf2')) {
+ // The output length is in NIBBLES (4-bits) if $raw_output is false!
+ if (! $raw_output) {
+ $key_length = $key_length * 2;
+ }
+ return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
+ }
+
+ $hash_length = Core::ourStrlen(\hash($algorithm, '', true));
+ $block_count = \ceil($key_length / $hash_length);
+
+ $output = '';
+ for ($i = 1; $i <= $block_count; $i++) {
+ // $i encoded as 4 bytes, big endian.
+ $last = $salt . \pack('N', $i);
+ // first iteration
+ $last = $xorsum = \hash_hmac($algorithm, $last, $password, true);
+ // perform the other $count - 1 iterations
+ for ($j = 1; $j < $count; $j++) {
+ /**
+ * @psalm-suppress InvalidOperand
+ */
+ $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true));
+ }
+ $output .= $xorsum;
+ }
+
+ if ($raw_output) {
+ return (string) Core::ourSubstr($output, 0, $key_length);
+ } else {
+ return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length));
+ }
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/Crypto.php b/api_candidatos/vendor/defuse/php-encryption/src/Crypto.php
new file mode 100644
index 0000000..f148db4
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/Crypto.php
@@ -0,0 +1,477 @@
+deriveKeys($salt);
+ $ekey = $keys->getEncryptionKey();
+ $akey = $keys->getAuthenticationKey();
+ $iv = Core::secureRandom(Core::BLOCK_BYTE_SIZE);
+
+ $ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv);
+ $auth = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true);
+ $ciphertext = $ciphertext . $auth;
+
+ if ($raw_binary) {
+ return $ciphertext;
+ }
+ return Encoding::binToHex($ciphertext);
+ }
+
+ /**
+ * Decrypts a ciphertext to a string with either a key or a password.
+ *
+ * @param string $ciphertext
+ * @param KeyOrPassword $secret
+ * @param bool $raw_binary
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
+ *
+ * @return string
+ */
+ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary)
+ {
+ RuntimeTests::runtimeTest();
+
+ if (! $raw_binary) {
+ try {
+ $ciphertext = Encoding::hexToBin($ciphertext);
+ } catch (Ex\BadFormatException $ex) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Ciphertext has invalid hex encoding.'
+ );
+ }
+ }
+
+ if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Ciphertext is too short.'
+ );
+ }
+
+ // Get and check the version header.
+ /** @var string $header */
+ $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
+ if ($header !== Core::CURRENT_VERSION) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Bad version header.'
+ );
+ }
+
+ // Get the salt.
+ /** @var string $salt */
+ $salt = Core::ourSubstr(
+ $ciphertext,
+ Core::HEADER_VERSION_SIZE,
+ Core::SALT_BYTE_SIZE
+ );
+ Core::ensureTrue(\is_string($salt));
+
+ // Get the IV.
+ /** @var string $iv */
+ $iv = Core::ourSubstr(
+ $ciphertext,
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
+ Core::BLOCK_BYTE_SIZE
+ );
+ Core::ensureTrue(\is_string($iv));
+
+ // Get the HMAC.
+ /** @var string $hmac */
+ $hmac = Core::ourSubstr(
+ $ciphertext,
+ Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
+ Core::MAC_BYTE_SIZE
+ );
+ Core::ensureTrue(\is_string($hmac));
+
+ // Get the actual encrypted ciphertext.
+ /** @var string $encrypted */
+ $encrypted = Core::ourSubstr(
+ $ciphertext,
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE +
+ Core::BLOCK_BYTE_SIZE,
+ Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
+ Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
+ );
+ Core::ensureTrue(\is_string($encrypted));
+
+ // Derive the separate encryption and authentication keys from the key
+ // or password, whichever it is.
+ $keys = $secret->deriveKeys($salt);
+
+ if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) {
+ $plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD);
+ return $plaintext;
+ } else {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Integrity check failed.'
+ );
+ }
+ }
+
+ /**
+ * Raw unauthenticated encryption (insecure on its own).
+ *
+ * @param string $plaintext
+ * @param string $key
+ * @param string $iv
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string
+ */
+ protected static function plainEncrypt(
+ $plaintext,
+ #[\SensitiveParameter]
+ $key,
+ #[\SensitiveParameter]
+ $iv
+ )
+ {
+ Core::ensureConstantExists('OPENSSL_RAW_DATA');
+ Core::ensureFunctionExists('openssl_encrypt');
+ /** @var string $ciphertext */
+ $ciphertext = \openssl_encrypt(
+ $plaintext,
+ Core::CIPHER_METHOD,
+ $key,
+ OPENSSL_RAW_DATA,
+ $iv
+ );
+
+ Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed');
+
+ return $ciphertext;
+ }
+
+ /**
+ * Raw unauthenticated decryption (insecure on its own).
+ *
+ * @param string $ciphertext
+ * @param string $key
+ * @param string $iv
+ * @param string $cipherMethod
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string
+ */
+ protected static function plainDecrypt(
+ $ciphertext,
+ #[\SensitiveParameter]
+ $key,
+ #[\SensitiveParameter]
+ $iv,
+ $cipherMethod
+ )
+ {
+ Core::ensureConstantExists('OPENSSL_RAW_DATA');
+ Core::ensureFunctionExists('openssl_decrypt');
+
+ /** @var string $plaintext */
+ $plaintext = \openssl_decrypt(
+ $ciphertext,
+ $cipherMethod,
+ $key,
+ OPENSSL_RAW_DATA,
+ $iv
+ );
+ Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.');
+
+ return $plaintext;
+ }
+
+ /**
+ * Verifies an HMAC without leaking information through side-channels.
+ *
+ * @param string $expected_hmac
+ * @param string $message
+ * @param string $key
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return bool
+ */
+ protected static function verifyHMAC(
+ $expected_hmac,
+ $message,
+ #[\SensitiveParameter]
+ $key
+ )
+ {
+ $message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true);
+ return Core::hashEquals($message_hmac, $expected_hmac);
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/DerivedKeys.php b/api_candidatos/vendor/defuse/php-encryption/src/DerivedKeys.php
new file mode 100644
index 0000000..86a48e5
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/DerivedKeys.php
@@ -0,0 +1,50 @@
+akey;
+ }
+
+ /**
+ * Returns the encryption key.
+ * @return string
+ */
+ public function getEncryptionKey()
+ {
+ return $this->ekey;
+ }
+
+ /**
+ * Constructor for DerivedKeys.
+ *
+ * @param string $akey
+ * @param string $ekey
+ */
+ public function __construct($akey, $ekey)
+ {
+ $this->akey = $akey;
+ $this->ekey = $ekey;
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/Encoding.php b/api_candidatos/vendor/defuse/php-encryption/src/Encoding.php
new file mode 100644
index 0000000..b14044f
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/Encoding.php
@@ -0,0 +1,277 @@
+> 4;
+ $hex .= \pack(
+ 'CC',
+ 87 + $b + ((($b - 10) >> 8) & ~38),
+ 87 + $c + ((($c - 10) >> 8) & ~38)
+ );
+ }
+ return $hex;
+ }
+
+ /**
+ * Converts a hexadecimal string into a byte string without leaking
+ * information through side channels.
+ *
+ * @param string $hex_string
+ *
+ * @throws Ex\BadFormatException
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string
+ * @psalm-suppress TypeDoesNotContainType
+ */
+ public static function hexToBin($hex_string)
+ {
+ $hex_pos = 0;
+ $bin = '';
+ $hex_len = Core::ourStrlen($hex_string);
+ $state = 0;
+ $c_acc = 0;
+
+ while ($hex_pos < $hex_len) {
+ $c = \ord($hex_string[$hex_pos]);
+ $c_num = $c ^ 48;
+ $c_num0 = ($c_num - 10) >> 8;
+ $c_alpha = ($c & ~32) - 55;
+ $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
+ if (($c_num0 | $c_alpha0) === 0) {
+ throw new Ex\BadFormatException(
+ 'Encoding::hexToBin() input is not a hex string.'
+ );
+ }
+ $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
+ if ($state === 0) {
+ $c_acc = $c_val * 16;
+ } else {
+ $bin .= \pack('C', $c_acc | $c_val);
+ }
+ $state ^= 1;
+ ++$hex_pos;
+ }
+ return $bin;
+ }
+
+ /**
+ * Remove trialing whitespace without table look-ups or branches.
+ *
+ * Calling this function may leak the length of the string as well as the
+ * number of trailing whitespace characters through side-channels.
+ *
+ * @param string $string
+ * @return string
+ */
+ public static function trimTrailingWhitespace($string = '')
+ {
+ $length = Core::ourStrlen($string);
+ if ($length < 1) {
+ return '';
+ }
+ do {
+ $prevLength = $length;
+ $last = $length - 1;
+ $chr = \ord($string[$last]);
+
+ /* Null Byte (0x00), a.k.a. \0 */
+ // if ($chr === 0x00) $length -= 1;
+ $sub = (($chr - 1) >> 8 ) & 1;
+ $length -= $sub;
+ $last -= $sub;
+
+ /* Horizontal Tab (0x09) a.k.a. \t */
+ $chr = \ord($string[$last]);
+ // if ($chr === 0x09) $length -= 1;
+ $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1;
+ $length -= $sub;
+ $last -= $sub;
+
+ /* New Line (0x0a), a.k.a. \n */
+ $chr = \ord($string[$last]);
+ // if ($chr === 0x0a) $length -= 1;
+ $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1;
+ $length -= $sub;
+ $last -= $sub;
+
+ /* Carriage Return (0x0D), a.k.a. \r */
+ $chr = \ord($string[$last]);
+ // if ($chr === 0x0d) $length -= 1;
+ $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1;
+ $length -= $sub;
+ $last -= $sub;
+
+ /* Space */
+ $chr = \ord($string[$last]);
+ // if ($chr === 0x20) $length -= 1;
+ $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1;
+ $length -= $sub;
+ } while ($prevLength !== $length && $length > 0);
+ return (string) Core::ourSubstr($string, 0, $length);
+ }
+
+ /*
+ * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS:
+ *
+ * The checksum introduces a potential security weakness. For example,
+ * suppose we apply a checksum to a key, and that an adversary has an
+ * exploit against the process containing the key, such that they can
+ * overwrite an arbitrary byte of memory and then cause the checksum to
+ * be verified and learn the result.
+ *
+ * In this scenario, the adversary can extract the key one byte at
+ * a time by overwriting it with their guess of its value and then
+ * asking if the checksum matches. If it does, their guess was right.
+ * This kind of attack may be more easy to implement and more reliable
+ * than a remote code execution attack.
+ *
+ * This attack also applies to authenticated encryption as a whole, in
+ * the situation where the adversary can overwrite a byte of the key
+ * and then cause a valid ciphertext to be decrypted, and then
+ * determine whether the MAC check passed or failed.
+ *
+ * By using the full SHA256 hash instead of truncating it, I'm ensuring
+ * that both ways of going about the attack are equivalently difficult.
+ * A shorter checksum of say 32 bits might be more useful to the
+ * adversary as an oracle in case their writes are coarser grained.
+ *
+ * Because the scenario assumes a serious vulnerability, we don't try
+ * to prevent attacks of this style.
+ */
+
+ /**
+ * INTERNAL USE ONLY: Applies a version header, applies a checksum, and
+ * then encodes a byte string into a range of printable ASCII characters.
+ *
+ * @param string $header
+ * @param string $bytes
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string
+ */
+ public static function saveBytesToChecksummedAsciiSafeString(
+ $header,
+ #[\SensitiveParameter]
+ $bytes
+ )
+ {
+ // Headers must be a constant length to prevent one type's header from
+ // being a prefix of another type's header, leading to ambiguity.
+ Core::ensureTrue(
+ Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES,
+ 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.'
+ );
+
+ return Encoding::binToHex(
+ $header .
+ $bytes .
+ \hash(
+ self::CHECKSUM_HASH_ALGO,
+ $header . $bytes,
+ true
+ )
+ );
+ }
+
+ /**
+ * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns
+ * the encoded byte string.
+ *
+ * @param string $expected_header
+ * @param string $string
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @throws Ex\BadFormatException
+ *
+ * @return string
+ */
+ public static function loadBytesFromChecksummedAsciiSafeString(
+ $expected_header,
+ #[\SensitiveParameter]
+ $string
+ )
+ {
+ // Headers must be a constant length to prevent one type's header from
+ // being a prefix of another type's header, leading to ambiguity.
+ Core::ensureTrue(
+ Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES,
+ 'Header must be 4 bytes.'
+ );
+
+ /* If you get an exception here when attempting to load from a file, first pass your
+ key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */
+ $bytes = Encoding::hexToBin($string);
+
+ /* Make sure we have enough bytes to get the version header and checksum. */
+ if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) {
+ throw new Ex\BadFormatException(
+ 'Encoded data is shorter than expected.'
+ );
+ }
+
+ /* Grab the version header. */
+ $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
+
+ if ($actual_header !== $expected_header) {
+ throw new Ex\BadFormatException(
+ 'Invalid header.'
+ );
+ }
+
+ /* Grab the bytes that are part of the checksum. */
+ $checked_bytes = (string) Core::ourSubstr(
+ $bytes,
+ 0,
+ Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE
+ );
+
+ /* Grab the included checksum. */
+ $checksum_a = (string) Core::ourSubstr(
+ $bytes,
+ Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE,
+ self::CHECKSUM_BYTE_SIZE
+ );
+
+ /* Re-compute the checksum. */
+ $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true);
+
+ /* Check if the checksum matches. */
+ if (! Core::hashEquals($checksum_a, $checksum_b)) {
+ throw new Ex\BadFormatException(
+ "Data is corrupted, the checksum doesn't match"
+ );
+ }
+
+ return (string) Core::ourSubstr(
+ $bytes,
+ self::SERIALIZE_HEADER_BYTES,
+ Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE
+ );
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/Exception/BadFormatException.php b/api_candidatos/vendor/defuse/php-encryption/src/Exception/BadFormatException.php
new file mode 100644
index 0000000..804d9c1
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/Exception/BadFormatException.php
@@ -0,0 +1,7 @@
+deriveKeys($file_salt);
+ $ekey = $keys->getEncryptionKey();
+ $akey = $keys->getAuthenticationKey();
+
+ $ivsize = Core::BLOCK_BYTE_SIZE;
+ $iv = Core::secureRandom($ivsize);
+
+ /* Initialize a streaming HMAC state. */
+ /** @var mixed $hmac */
+ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
+ Core::ensureTrue(
+ \is_resource($hmac) || \is_object($hmac),
+ 'Cannot initialize a hash context'
+ );
+
+ /* Write the header, salt, and IV. */
+ self::writeBytes(
+ $outputHandle,
+ Core::CURRENT_VERSION . $file_salt . $iv,
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize
+ );
+
+ /* Add the header, salt, and IV to the HMAC. */
+ \hash_update($hmac, Core::CURRENT_VERSION);
+ \hash_update($hmac, $file_salt);
+ \hash_update($hmac, $iv);
+
+ /* $thisIv will be incremented after each call to the encryption. */
+ $thisIv = $iv;
+
+ /* How many blocks do we encrypt at a time? We increment by this value. */
+ /**
+ * @psalm-suppress RedundantCast
+ */
+ $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);
+
+ /* Loop until we reach the end of the input file. */
+ $at_file_end = false;
+ while (! (\feof($inputHandle) || $at_file_end)) {
+ /* Find out if we can read a full buffer, or only a partial one. */
+ /** @var int */
+ $pos = \ftell($inputHandle);
+ if (!\is_int($pos)) {
+ throw new Ex\IOException(
+ 'Could not get current position in input file during encryption'
+ );
+ }
+ if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) {
+ /* We're at the end of the file, so we need to break out of the loop. */
+ $at_file_end = true;
+ $read = self::readBytes(
+ $inputHandle,
+ $inputSize - $pos
+ );
+ } else {
+ $read = self::readBytes(
+ $inputHandle,
+ Core::BUFFER_BYTE_SIZE
+ );
+ }
+
+ /* Encrypt this buffer. */
+ /** @var string */
+ $encrypted = \openssl_encrypt(
+ $read,
+ Core::CIPHER_METHOD,
+ $ekey,
+ OPENSSL_RAW_DATA,
+ $thisIv
+ );
+
+ Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error');
+
+ /* Write this buffer's ciphertext. */
+ self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
+ /* Add this buffer's ciphertext to the HMAC. */
+ \hash_update($hmac, $encrypted);
+
+ /* Increment the counter by the number of blocks in a buffer. */
+ $thisIv = Core::incrementCounter($thisIv, $inc);
+ /* WARNING: Usually, unless the file is a multiple of the buffer
+ * size, $thisIv will contain an incorrect value here on the last
+ * iteration of this loop. */
+ }
+
+ /* Get the HMAC and append it to the ciphertext. */
+ $final_mac = \hash_final($hmac, true);
+ self::writeBytes($outputHandle, $final_mac, Core::MAC_BYTE_SIZE);
+ }
+
+ /**
+ * Decrypts a file-backed resource with either a key or a password.
+ *
+ * @param resource $inputHandle
+ * @param resource $outputHandle
+ * @param KeyOrPassword $secret
+ * @return void
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @throws Ex\IOException
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
+ * @psalm-suppress PossiblyInvalidArgument
+ * Fixes erroneous errors caused by PHP 7.2 switching the return value
+ * of hash_init from a resource to a HashContext.
+ */
+ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
+ {
+ if (! \is_resource($inputHandle)) {
+ throw new Ex\IOException(
+ 'Input handle must be a resource!'
+ );
+ }
+ if (! \is_resource($outputHandle)) {
+ throw new Ex\IOException(
+ 'Output handle must be a resource!'
+ );
+ }
+
+ /* Make sure the file is big enough for all the reads we need to do. */
+ $stat = \fstat($inputHandle);
+ if ($stat['size'] < Core::MINIMUM_CIPHERTEXT_SIZE) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Input file is too small to have been created by this library.'
+ );
+ }
+
+ /* Check the version header. */
+ $header = self::readBytes($inputHandle, Core::HEADER_VERSION_SIZE);
+ if ($header !== Core::CURRENT_VERSION) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Bad version header.'
+ );
+ }
+
+ /* Get the salt. */
+ $file_salt = self::readBytes($inputHandle, Core::SALT_BYTE_SIZE);
+
+ /* Get the IV. */
+ $ivsize = Core::BLOCK_BYTE_SIZE;
+ $iv = self::readBytes($inputHandle, $ivsize);
+
+ /* Derive the authentication and encryption keys. */
+ $keys = $secret->deriveKeys($file_salt);
+ $ekey = $keys->getEncryptionKey();
+ $akey = $keys->getAuthenticationKey();
+
+ /* We'll store the MAC of each buffer-sized chunk as we verify the
+ * actual MAC, so that we can check them again when decrypting. */
+ $macs = [];
+
+ /* $thisIv will be incremented after each call to the decryption. */
+ $thisIv = $iv;
+
+ /* How many blocks do we encrypt at a time? We increment by this value. */
+ /**
+ * @psalm-suppress RedundantCast
+ */
+ $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);
+
+ /* Get the HMAC. */
+ if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === -1) {
+ throw new Ex\IOException(
+ 'Cannot seek to beginning of MAC within input file'
+ );
+ }
+
+ /* Get the position of the last byte in the actual ciphertext. */
+ /** @var int $cipher_end */
+ $cipher_end = \ftell($inputHandle);
+ if (!\is_int($cipher_end)) {
+ throw new Ex\IOException(
+ 'Cannot read input file'
+ );
+ }
+ /* We have the position of the first byte of the HMAC. Go back by one. */
+ --$cipher_end;
+
+ /* Read the HMAC. */
+ /** @var string $stored_mac */
+ $stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE);
+
+ /* Initialize a streaming HMAC state. */
+ /** @var mixed $hmac */
+ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
+ Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), 'Cannot initialize a hash context');
+
+ /* Reset file pointer to the beginning of the file after the header */
+ if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) {
+ throw new Ex\IOException(
+ 'Cannot read seek within input file'
+ );
+ }
+
+ /* Seek to the start of the actual ciphertext. */
+ if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === -1) {
+ throw new Ex\IOException(
+ 'Cannot seek input file to beginning of ciphertext'
+ );
+ }
+
+ /* PASS #1: Calculating the HMAC. */
+
+ \hash_update($hmac, $header);
+ \hash_update($hmac, $file_salt);
+ \hash_update($hmac, $iv);
+ /** @var mixed $hmac2 */
+ $hmac2 = \hash_copy($hmac);
+
+ $break = false;
+ while (! $break) {
+ /** @var int $pos */
+ $pos = \ftell($inputHandle);
+ if (!\is_int($pos)) {
+ throw new Ex\IOException(
+ 'Could not get current position in input file during decryption'
+ );
+ }
+
+ /* Read the next buffer-sized chunk (or less). */
+ if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
+ $break = true;
+ $read = self::readBytes(
+ $inputHandle,
+ $cipher_end - $pos + 1
+ );
+ } else {
+ $read = self::readBytes(
+ $inputHandle,
+ Core::BUFFER_BYTE_SIZE
+ );
+ }
+
+ /* Update the HMAC. */
+ \hash_update($hmac, $read);
+
+ /* Remember this buffer-sized chunk's HMAC. */
+ /** @var mixed $chunk_mac */
+ $chunk_mac = \hash_copy($hmac);
+ Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context');
+ $macs []= \hash_final($chunk_mac);
+ }
+
+ /* Get the final HMAC, which should match the stored one. */
+ /** @var string $final_mac */
+ $final_mac = \hash_final($hmac, true);
+
+ /* Verify the HMAC. */
+ if (! Core::hashEquals($final_mac, $stored_mac)) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'Integrity check failed.'
+ );
+ }
+
+ /* PASS #2: Decrypt and write output. */
+
+ /* Rewind to the start of the actual ciphertext. */
+ if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) {
+ throw new Ex\IOException(
+ 'Could not move the input file pointer during decryption'
+ );
+ }
+
+ $at_file_end = false;
+ while (! $at_file_end) {
+ /** @var int $pos */
+ $pos = \ftell($inputHandle);
+ if (!\is_int($pos)) {
+ throw new Ex\IOException(
+ 'Could not get current position in input file during decryption'
+ );
+ }
+
+ /* Read the next buffer-sized chunk (or less). */
+ if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
+ $at_file_end = true;
+ $read = self::readBytes(
+ $inputHandle,
+ $cipher_end - $pos + 1
+ );
+ } else {
+ $read = self::readBytes(
+ $inputHandle,
+ Core::BUFFER_BYTE_SIZE
+ );
+ }
+
+ /* Recalculate the MAC (so far) and compare it with the one we
+ * remembered from pass #1 to ensure attackers didn't change the
+ * ciphertext after MAC verification. */
+ \hash_update($hmac2, $read);
+ /** @var mixed $calc_mac */
+ $calc_mac = \hash_copy($hmac2);
+ Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context');
+ $calc = \hash_final($calc_mac);
+
+ if (empty($macs)) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'File was modified after MAC verification'
+ );
+ } elseif (! Core::hashEquals(\array_shift($macs), $calc)) {
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ 'File was modified after MAC verification'
+ );
+ }
+
+ /* Decrypt this buffer-sized chunk. */
+ /** @var string $decrypted */
+ $decrypted = \openssl_decrypt(
+ $read,
+ Core::CIPHER_METHOD,
+ $ekey,
+ OPENSSL_RAW_DATA,
+ $thisIv
+ );
+ Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error');
+
+ /* Write the plaintext to the output file. */
+ self::writeBytes(
+ $outputHandle,
+ $decrypted,
+ Core::ourStrlen($decrypted)
+ );
+
+ /* Increment the IV by the amount of blocks in a buffer. */
+ /** @var string $thisIv */
+ $thisIv = Core::incrementCounter($thisIv, $inc);
+ /* WARNING: Usually, unless the file is a multiple of the buffer
+ * size, $thisIv will contain an incorrect value here on the last
+ * iteration of this loop. */
+ }
+ }
+
+ /**
+ * Read from a stream; prevent partial reads.
+ *
+ * @param resource $stream
+ * @param int $num_bytes
+ * @return string
+ *
+ * @throws Ex\IOException
+ * @throws Ex\EnvironmentIsBrokenException
+ */
+ public static function readBytes($stream, $num_bytes)
+ {
+ Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes');
+
+ if ($num_bytes === 0) {
+ return '';
+ }
+
+ $buf = '';
+ $remaining = $num_bytes;
+ while ($remaining > 0 && ! \feof($stream)) {
+ /** @var string $read */
+ $read = \fread($stream, $remaining);
+ if (!\is_string($read)) {
+ throw new Ex\IOException(
+ 'Could not read from the file'
+ );
+ }
+ $buf .= $read;
+ $remaining -= Core::ourStrlen($read);
+ }
+ if (Core::ourStrlen($buf) !== $num_bytes) {
+ throw new Ex\IOException(
+ 'Tried to read past the end of the file'
+ );
+ }
+ return $buf;
+ }
+
+ /**
+ * Write to a stream; prevents partial writes.
+ *
+ * @param resource $stream
+ * @param string $buf
+ * @param int $num_bytes
+ * @return int
+ *
+ * @throws Ex\IOException
+ */
+ public static function writeBytes($stream, $buf, $num_bytes = null)
+ {
+ $bufSize = Core::ourStrlen($buf);
+ if ($num_bytes === null) {
+ $num_bytes = $bufSize;
+ }
+ if ($num_bytes > $bufSize) {
+ throw new Ex\IOException(
+ 'Trying to write more bytes than the buffer contains.'
+ );
+ }
+ if ($num_bytes < 0) {
+ throw new Ex\IOException(
+ 'Tried to write less than 0 bytes'
+ );
+ }
+ $remaining = $num_bytes;
+ while ($remaining > 0) {
+ /** @var int $written */
+ $written = \fwrite($stream, $buf, $remaining);
+ if (!\is_int($written)) {
+ throw new Ex\IOException(
+ 'Could not write to the file'
+ );
+ }
+ $buf = (string) Core::ourSubstr($buf, $written, null);
+ $remaining -= $written;
+ }
+ return $num_bytes;
+ }
+
+ /**
+ * Returns the last PHP error's or warning's message string.
+ *
+ * @return string
+ */
+ private static function getLastErrorMessage()
+ {
+ $error = error_get_last();
+ if ($error === null) {
+ return '[no PHP error, or you have a custom error handler set]';
+ } else {
+ return $error['message'];
+ }
+ }
+
+ /**
+ * PHPUnit sets an error handler, which prevents getLastErrorMessage() from working,
+ * because error_get_last does not work when custom handlers are set.
+ *
+ * This is a workaround, which should be a no-op in production deployments, to make
+ * getLastErrorMessage() return the error messages that the PHPUnit tests expect.
+ *
+ * If, in a production deployment, a custom error handler is set, the exception
+ * handling will still work as usual, but the error messages will be confusing.
+ *
+ * @return void
+ */
+ private static function removePHPUnitErrorHandler() {
+ if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
+ set_error_handler(null);
+ }
+ }
+
+ /**
+ * Undoes what removePHPUnitErrorHandler did.
+ *
+ * @return void
+ */
+ private static function restorePHPUnitErrorHandler() {
+ if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
+ restore_error_handler();
+ }
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/Key.php b/api_candidatos/vendor/defuse/php-encryption/src/Key.php
new file mode 100644
index 0000000..1767d1f
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/Key.php
@@ -0,0 +1,101 @@
+key_bytes
+ );
+ }
+
+ /**
+ * Gets the raw bytes of the key.
+ *
+ * @return string
+ */
+ public function getRawBytes()
+ {
+ return $this->key_bytes;
+ }
+
+ /**
+ * Constructs a new Key object from a string of raw bytes.
+ *
+ * @param string $bytes
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ */
+ private function __construct(
+ #[\SensitiveParameter]
+ $bytes
+ )
+ {
+ Core::ensureTrue(
+ Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE,
+ 'Bad key length.'
+ );
+ $this->key_bytes = $bytes;
+ }
+
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/KeyOrPassword.php b/api_candidatos/vendor/defuse/php-encryption/src/KeyOrPassword.php
new file mode 100644
index 0000000..3850655
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/KeyOrPassword.php
@@ -0,0 +1,156 @@
+secret_type === self::SECRET_TYPE_KEY) {
+ Core::ensureTrue($this->secret instanceof Key);
+ /**
+ * @psalm-suppress PossiblyInvalidMethodCall
+ */
+ $akey = Core::HKDF(
+ Core::HASH_FUNCTION_NAME,
+ $this->secret->getRawBytes(),
+ Core::KEY_BYTE_SIZE,
+ Core::AUTHENTICATION_INFO_STRING,
+ $salt
+ );
+ /**
+ * @psalm-suppress PossiblyInvalidMethodCall
+ */
+ $ekey = Core::HKDF(
+ Core::HASH_FUNCTION_NAME,
+ $this->secret->getRawBytes(),
+ Core::KEY_BYTE_SIZE,
+ Core::ENCRYPTION_INFO_STRING,
+ $salt
+ );
+ return new DerivedKeys($akey, $ekey);
+ } elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) {
+ Core::ensureTrue(\is_string($this->secret));
+ /* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in
+ * GitHub issue #230. The fix is to pre-hash the password to ensure
+ * it is short. We do the prehashing here instead of in pbkdf2() so
+ * that pbkdf2() still computes the function as defined by the
+ * standard. */
+
+ /**
+ * @psalm-suppress PossiblyInvalidArgument
+ */
+ $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true);
+
+ $prekey = Core::pbkdf2(
+ Core::HASH_FUNCTION_NAME,
+ $prehash,
+ $salt,
+ self::PBKDF2_ITERATIONS,
+ Core::KEY_BYTE_SIZE,
+ true
+ );
+ $akey = Core::HKDF(
+ Core::HASH_FUNCTION_NAME,
+ $prekey,
+ Core::KEY_BYTE_SIZE,
+ Core::AUTHENTICATION_INFO_STRING,
+ $salt
+ );
+ /* Note the cryptographic re-use of $salt here. */
+ $ekey = Core::HKDF(
+ Core::HASH_FUNCTION_NAME,
+ $prekey,
+ Core::KEY_BYTE_SIZE,
+ Core::ENCRYPTION_INFO_STRING,
+ $salt
+ );
+ return new DerivedKeys($akey, $ekey);
+ } else {
+ throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
+ }
+ }
+
+ /**
+ * Constructor for KeyOrPassword.
+ *
+ * @param int $secret_type
+ * @param mixed $secret (either a Key or a password string)
+ */
+ private function __construct(
+ $secret_type,
+ #[\SensitiveParameter]
+ $secret
+ )
+ {
+ // The constructor is private, so these should never throw.
+ if ($secret_type === self::SECRET_TYPE_KEY) {
+ Core::ensureTrue($secret instanceof Key);
+ } elseif ($secret_type === self::SECRET_TYPE_PASSWORD) {
+ Core::ensureTrue(\is_string($secret));
+ } else {
+ throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
+ }
+ $this->secret_type = $secret_type;
+ $this->secret = $secret;
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php b/api_candidatos/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php
new file mode 100644
index 0000000..7d90ed1
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php
@@ -0,0 +1,159 @@
+saveToAsciiSafeString(),
+ \hash(Core::HASH_FUNCTION_NAME, $password, true),
+ true
+ );
+
+ return new KeyProtectedByPassword($encrypted_key);
+ }
+
+ /**
+ * Loads a KeyProtectedByPassword from its encoded form.
+ *
+ * @param string $saved_key_string
+ *
+ * @throws Ex\BadFormatException
+ *
+ * @return KeyProtectedByPassword
+ */
+ public static function loadFromAsciiSafeString(
+ #[\SensitiveParameter]
+ $saved_key_string
+ )
+ {
+ $encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString(
+ self::PASSWORD_KEY_CURRENT_VERSION,
+ $saved_key_string
+ );
+ return new KeyProtectedByPassword($encrypted_key);
+ }
+
+ /**
+ * Encodes the KeyProtectedByPassword into a string of printable ASCII
+ * characters.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ *
+ * @return string
+ */
+ public function saveToAsciiSafeString()
+ {
+ return Encoding::saveBytesToChecksummedAsciiSafeString(
+ self::PASSWORD_KEY_CURRENT_VERSION,
+ $this->encrypted_key
+ );
+ }
+
+ /**
+ * Decrypts the protected key, returning an unprotected Key object that can
+ * be used for encryption and decryption.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
+ *
+ * @param string $password
+ * @return Key
+ */
+ public function unlockKey(
+ #[\SensitiveParameter]
+ $password
+ )
+ {
+ try {
+ $inner_key_encoded = Crypto::decryptWithPassword(
+ $this->encrypted_key,
+ \hash(Core::HASH_FUNCTION_NAME, $password, true),
+ true
+ );
+ return Key::loadFromAsciiSafeString($inner_key_encoded);
+ } catch (Ex\BadFormatException $ex) {
+ /* This should never happen unless an attacker replaced the
+ * encrypted key ciphertext with some other ciphertext that was
+ * encrypted with the same password. We transform the exception type
+ * here in order to make the API simpler, avoiding the need to
+ * document that this method might throw an Ex\BadFormatException. */
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
+ "The decrypted key was found to be in an invalid format. " .
+ "This very likely indicates it was modified by an attacker."
+ );
+ }
+ }
+
+ /**
+ * Changes the password.
+ *
+ * @param string $current_password
+ * @param string $new_password
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
+ *
+ * @return KeyProtectedByPassword
+ */
+ public function changePassword(
+ #[\SensitiveParameter]
+ $current_password,
+ #[\SensitiveParameter]
+ $new_password
+ )
+ {
+ $inner_key = $this->unlockKey($current_password);
+ /* The password is hashed as a form of poor-man's domain separation
+ * between this use of encryptWithPassword() and other uses of
+ * encryptWithPassword() that the user may also be using as part of the
+ * same protocol. */
+ $encrypted_key = Crypto::encryptWithPassword(
+ $inner_key->saveToAsciiSafeString(),
+ \hash(Core::HASH_FUNCTION_NAME, $new_password, true),
+ true
+ );
+
+ $this->encrypted_key = $encrypted_key;
+
+ return $this;
+ }
+
+ /**
+ * Constructor for KeyProtectedByPassword.
+ *
+ * @param string $encrypted_key
+ */
+ private function __construct($encrypted_key)
+ {
+ $this->encrypted_key = $encrypted_key;
+ }
+}
diff --git a/api_candidatos/vendor/defuse/php-encryption/src/RuntimeTests.php b/api_candidatos/vendor/defuse/php-encryption/src/RuntimeTests.php
new file mode 100644
index 0000000..65ce55d
--- /dev/null
+++ b/api_candidatos/vendor/defuse/php-encryption/src/RuntimeTests.php
@@ -0,0 +1,228 @@
+getRawBytes()) === Core::KEY_BYTE_SIZE);
+
+ Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING);
+ } catch (Ex\EnvironmentIsBrokenException $ex) {
+ // Do this, otherwise it will stay in the "tests are running" state.
+ $test_state = 3;
+ throw $ex;
+ }
+
+ // Change this to '0' make the tests always re-run (for benchmarking).
+ $test_state = 1;
+ }
+
+ /**
+ * High-level tests of Crypto operations.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @return void
+ */
+ private static function testEncryptDecrypt()
+ {
+ $key = Key::createNewRandomKey();
+ $data = "EnCrYpT EvErYThInG\x00\x00";
+
+ // Make sure encrypting then decrypting doesn't change the message.
+ $ciphertext = Crypto::encrypt($data, $key, true);
+ try {
+ $decrypted = Crypto::decrypt($ciphertext, $key, true);
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $ex) {
+ // It's important to catch this and change it into a
+ // Ex\EnvironmentIsBrokenException, otherwise a test failure could trick
+ // the user into thinking it's just an invalid ciphertext!
+ throw new Ex\EnvironmentIsBrokenException();
+ }
+ Core::ensureTrue($decrypted === $data);
+
+ // Modifying the ciphertext: Appending a string.
+ try {
+ Crypto::decrypt($ciphertext . 'a', $key, true);
+ throw new Ex\EnvironmentIsBrokenException();
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
+ }
+
+ // Modifying the ciphertext: Changing an HMAC byte.
+ $indices_to_change = [
+ 0, // The header.
+ Core::HEADER_VERSION_SIZE + 1, // the salt
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext
+ ];
+
+ foreach ($indices_to_change as $index) {
+ try {
+ $ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256);
+ Crypto::decrypt($ciphertext, $key, true);
+ throw new Ex\EnvironmentIsBrokenException();
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
+ }
+ }
+
+ // Decrypting with the wrong key.
+ $key = Key::createNewRandomKey();
+ $data = 'abcdef';
+ $ciphertext = Crypto::encrypt($data, $key, true);
+ $wrong_key = Key::createNewRandomKey();
+ try {
+ Crypto::decrypt($ciphertext, $wrong_key, true);
+ throw new Ex\EnvironmentIsBrokenException();
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
+ }
+
+ // Ciphertext too small.
+ $key = Key::createNewRandomKey();
+ $ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1);
+ try {
+ Crypto::decrypt($ciphertext, $key, true);
+ throw new Ex\EnvironmentIsBrokenException();
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
+ }
+ }
+
+ /**
+ * Test HKDF against test vectors.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @return void
+ */
+ private static function HKDFTestVector()
+ {
+ // HKDF test vectors from RFC 5869
+
+ // Test Case 1
+ $ikm = \str_repeat("\x0b", 22);
+ $salt = Encoding::hexToBin('000102030405060708090a0b0c');
+ $info = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9');
+ $length = 42;
+ $okm = Encoding::hexToBin(
+ '3cb25f25faacd57a90434f64d0362f2a' .
+ '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' .
+ '34007208d5b887185865'
+ );
+ $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt);
+ Core::ensureTrue($computed_okm === $okm);
+
+ // Test Case 7
+ $ikm = \str_repeat("\x0c", 22);
+ $length = 42;
+ $okm = Encoding::hexToBin(
+ '2c91117204d745f3500d636a62f64f0a' .
+ 'b3bae548aa53d423b0d1f27ebba6f5e5' .
+ '673a081d70cce7acfc48'
+ );
+ $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null);
+ Core::ensureTrue($computed_okm === $okm);
+ }
+
+ /**
+ * Test HMAC against test vectors.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @return void
+ */
+ private static function HMACTestVector()
+ {
+ // HMAC test vector From RFC 4231 (Test Case 1)
+ $key = \str_repeat("\x0b", 20);
+ $data = 'Hi There';
+ $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7';
+ Core::ensureTrue(
+ \hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct
+ );
+ }
+
+ /**
+ * Test AES against test vectors.
+ *
+ * @throws Ex\EnvironmentIsBrokenException
+ * @return void
+ */
+ private static function AESTestVector()
+ {
+ // AES CTR mode test vector from NIST SP 800-38A
+ $key = Encoding::hexToBin(
+ '603deb1015ca71be2b73aef0857d7781' .
+ '1f352c073b6108d72d9810a30914dff4'
+ );
+ $iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
+ $plaintext = Encoding::hexToBin(
+ '6bc1bee22e409f96e93d7e117393172a' .
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' .
+ '30c81c46a35ce411e5fbc1191a0a52ef' .
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ );
+ $ciphertext = Encoding::hexToBin(
+ '601ec313775789a5b7a7f504bbf3d228' .
+ 'f443e3ca4d62b59aca84e990cacaf5c5' .
+ '2b0930daa23de94ce87017ba2d84988d' .
+ 'dfc9c58db67aada613c2dd08457941a6'
+ );
+
+ $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv);
+ Core::ensureTrue($computed_ciphertext === $ciphertext);
+
+ $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD);
+ Core::ensureTrue($computed_plaintext === $plaintext);
+ }
+}
diff --git a/api_candidatos/vendor/fig/http-message-util/.gitignore b/api_candidatos/vendor/fig/http-message-util/.gitignore
new file mode 100644
index 0000000..48b8bf9
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/.gitignore
@@ -0,0 +1 @@
+vendor/
diff --git a/api_candidatos/vendor/fig/http-message-util/CHANGELOG.md b/api_candidatos/vendor/fig/http-message-util/CHANGELOG.md
new file mode 100644
index 0000000..1a02e54
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/CHANGELOG.md
@@ -0,0 +1,147 @@
+# Changelog
+
+All notable changes to this project will be documented in this file, in reverse chronological order by release.
+
+## 1.1.5 - 2020-11-24
+
+### Added
+
+- [#19](https://github.com/php-fig/http-message-util/pull/19) adds support for PHP 8.
+
+### Changed
+
+- Nothing.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
+## 1.1.4 - 2020-02-05
+
+### Added
+
+- Nothing.
+
+### Changed
+
+- Nothing.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- [#15](https://github.com/php-fig/http-message-util/pull/15) removes the dependency on psr/http-message, as it is not technically necessary for usage of this package.
+
+### Fixed
+
+- Nothing.
+
+## 1.1.3 - 2018-11-19
+
+### Added
+
+- [#10](https://github.com/php-fig/http-message-util/pull/10) adds the constants `StatusCodeInterface::STATUS_EARLY_HINTS` (103) and
+ `StatusCodeInterface::STATUS_TOO_EARLY` (425).
+
+### Changed
+
+- Nothing.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
+## 1.1.2 - 2017-02-09
+
+### Added
+
+- [#4](https://github.com/php-fig/http-message-util/pull/4) adds the constant
+ `StatusCodeInterface::STATUS_MISDIRECTED_REQUEST` (421).
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
+## 1.1.1 - 2017-02-06
+
+### Added
+
+- [#3](https://github.com/php-fig/http-message-util/pull/3) adds the constant
+ `StatusCodeInterface::STATUS_IM_A_TEAPOT` (418).
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
+## 1.1.0 - 2016-09-19
+
+### Added
+
+- [#1](https://github.com/php-fig/http-message-util/pull/1) adds
+ `Fig\Http\Message\StatusCodeInterface`, with constants named after common
+ status reason phrases, with values indicating the status codes themselves.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
+## 1.0.0 - 2017-08-05
+
+### Added
+
+- Adds `Fig\Http\Message\RequestMethodInterface`, with constants covering the
+ most common HTTP request methods as specified by the IETF.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
diff --git a/api_candidatos/vendor/fig/http-message-util/LICENSE b/api_candidatos/vendor/fig/http-message-util/LICENSE
new file mode 100644
index 0000000..e2fa347
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2016 PHP Framework Interoperability Group
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/api_candidatos/vendor/fig/http-message-util/README.md b/api_candidatos/vendor/fig/http-message-util/README.md
new file mode 100644
index 0000000..ea5b5aa
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/README.md
@@ -0,0 +1,17 @@
+# PSR Http Message Util
+
+This repository holds utility classes and constants to facilitate common
+operations of [PSR-7](https://www.php-fig.org/psr/psr-7/); the primary purpose is
+to provide constants for referring to request methods, response status codes and
+messages, and potentially common headers.
+
+Implementation of PSR-7 interfaces is **not** within the scope of this package.
+
+## Installation
+
+Install by adding the package as a [Composer](https://getcomposer.org)
+requirement:
+
+```bash
+$ composer require fig/http-message-util
+```
diff --git a/api_candidatos/vendor/fig/http-message-util/composer.json b/api_candidatos/vendor/fig/http-message-util/composer.json
new file mode 100644
index 0000000..8645893
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "fig/http-message-util",
+ "description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
+ "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": "^5.3 || ^7.0 || ^8.0"
+ },
+ "suggest": {
+ "psr/http-message": "The package containing the PSR-7 interfaces"
+ },
+ "autoload": {
+ "psr-4": {
+ "Fig\\Http\\Message\\": "src/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/fig/http-message-util/src/RequestMethodInterface.php b/api_candidatos/vendor/fig/http-message-util/src/RequestMethodInterface.php
new file mode 100644
index 0000000..97d9a93
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/src/RequestMethodInterface.php
@@ -0,0 +1,34 @@
+
+ * class RequestFactory implements RequestMethodInterface
+ * {
+ * public static function factory(
+ * $uri = '/',
+ * $method = self::METHOD_GET,
+ * $data = []
+ * ) {
+ * }
+ * }
+ *
+ */
+interface RequestMethodInterface
+{
+ const METHOD_HEAD = 'HEAD';
+ const METHOD_GET = 'GET';
+ const METHOD_POST = 'POST';
+ const METHOD_PUT = 'PUT';
+ const METHOD_PATCH = 'PATCH';
+ const METHOD_DELETE = 'DELETE';
+ const METHOD_PURGE = 'PURGE';
+ const METHOD_OPTIONS = 'OPTIONS';
+ const METHOD_TRACE = 'TRACE';
+ const METHOD_CONNECT = 'CONNECT';
+}
diff --git a/api_candidatos/vendor/fig/http-message-util/src/StatusCodeInterface.php b/api_candidatos/vendor/fig/http-message-util/src/StatusCodeInterface.php
new file mode 100644
index 0000000..99b7e78
--- /dev/null
+++ b/api_candidatos/vendor/fig/http-message-util/src/StatusCodeInterface.php
@@ -0,0 +1,107 @@
+
+ * class ResponseFactory implements StatusCodeInterface
+ * {
+ * public function createResponse($code = self::STATUS_OK)
+ * {
+ * }
+ * }
+ *
+ */
+interface StatusCodeInterface
+{
+ // Informational 1xx
+ const STATUS_CONTINUE = 100;
+ const STATUS_SWITCHING_PROTOCOLS = 101;
+ const STATUS_PROCESSING = 102;
+ const STATUS_EARLY_HINTS = 103;
+ // Successful 2xx
+ const STATUS_OK = 200;
+ const STATUS_CREATED = 201;
+ const STATUS_ACCEPTED = 202;
+ const STATUS_NON_AUTHORITATIVE_INFORMATION = 203;
+ const STATUS_NO_CONTENT = 204;
+ const STATUS_RESET_CONTENT = 205;
+ const STATUS_PARTIAL_CONTENT = 206;
+ const STATUS_MULTI_STATUS = 207;
+ const STATUS_ALREADY_REPORTED = 208;
+ const STATUS_IM_USED = 226;
+ // Redirection 3xx
+ const STATUS_MULTIPLE_CHOICES = 300;
+ const STATUS_MOVED_PERMANENTLY = 301;
+ const STATUS_FOUND = 302;
+ const STATUS_SEE_OTHER = 303;
+ const STATUS_NOT_MODIFIED = 304;
+ const STATUS_USE_PROXY = 305;
+ const STATUS_RESERVED = 306;
+ const STATUS_TEMPORARY_REDIRECT = 307;
+ const STATUS_PERMANENT_REDIRECT = 308;
+ // Client Errors 4xx
+ const STATUS_BAD_REQUEST = 400;
+ const STATUS_UNAUTHORIZED = 401;
+ const STATUS_PAYMENT_REQUIRED = 402;
+ const STATUS_FORBIDDEN = 403;
+ const STATUS_NOT_FOUND = 404;
+ const STATUS_METHOD_NOT_ALLOWED = 405;
+ const STATUS_NOT_ACCEPTABLE = 406;
+ const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407;
+ const STATUS_REQUEST_TIMEOUT = 408;
+ const STATUS_CONFLICT = 409;
+ const STATUS_GONE = 410;
+ const STATUS_LENGTH_REQUIRED = 411;
+ const STATUS_PRECONDITION_FAILED = 412;
+ const STATUS_PAYLOAD_TOO_LARGE = 413;
+ const STATUS_URI_TOO_LONG = 414;
+ const STATUS_UNSUPPORTED_MEDIA_TYPE = 415;
+ const STATUS_RANGE_NOT_SATISFIABLE = 416;
+ const STATUS_EXPECTATION_FAILED = 417;
+ const STATUS_IM_A_TEAPOT = 418;
+ const STATUS_MISDIRECTED_REQUEST = 421;
+ const STATUS_UNPROCESSABLE_ENTITY = 422;
+ const STATUS_LOCKED = 423;
+ const STATUS_FAILED_DEPENDENCY = 424;
+ const STATUS_TOO_EARLY = 425;
+ const STATUS_UPGRADE_REQUIRED = 426;
+ const STATUS_PRECONDITION_REQUIRED = 428;
+ const STATUS_TOO_MANY_REQUESTS = 429;
+ const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
+ const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
+ // Server Errors 5xx
+ const STATUS_INTERNAL_SERVER_ERROR = 500;
+ const STATUS_NOT_IMPLEMENTED = 501;
+ const STATUS_BAD_GATEWAY = 502;
+ const STATUS_SERVICE_UNAVAILABLE = 503;
+ const STATUS_GATEWAY_TIMEOUT = 504;
+ const STATUS_VERSION_NOT_SUPPORTED = 505;
+ const STATUS_VARIANT_ALSO_NEGOTIATES = 506;
+ const STATUS_INSUFFICIENT_STORAGE = 507;
+ const STATUS_LOOP_DETECTED = 508;
+ const STATUS_NOT_EXTENDED = 510;
+ const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511;
+}
diff --git a/api_candidatos/vendor/lcobucci/clock/LICENSE b/api_candidatos/vendor/lcobucci/clock/LICENSE
new file mode 100644
index 0000000..58ea944
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/clock/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Luís Cobucci
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/api_candidatos/vendor/lcobucci/clock/composer.json b/api_candidatos/vendor/lcobucci/clock/composer.json
new file mode 100644
index 0000000..32dfab9
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/clock/composer.json
@@ -0,0 +1,48 @@
+{
+ "name": "lcobucci/clock",
+ "description": "Yet another clock abstraction",
+ "license": "MIT",
+ "type": "library",
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com"
+ }
+ ],
+ "require": {
+ "php": "~8.1.0 || ~8.2.0",
+ "stella-maris/clock": "^0.1.7"
+ },
+ "require-dev": {
+ "infection/infection": "^0.26",
+ "lcobucci/coding-standard": "^9.0",
+ "phpstan/extension-installer": "^1.2",
+ "phpstan/phpstan": "^1.9.4",
+ "phpstan/phpstan-deprecation-rules": "^1.1.1",
+ "phpstan/phpstan-phpunit": "^1.3.2",
+ "phpstan/phpstan-strict-rules": "^1.4.4",
+ "phpunit/phpunit": "^9.5.27"
+ },
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\Clock\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Lcobucci\\Clock\\": "test"
+ }
+ },
+ "config": {
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "infection/extension-installer": true,
+ "phpstan/extension-installer": true
+ }
+ },
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/clock/renovate.json b/api_candidatos/vendor/lcobucci/clock/renovate.json
new file mode 100644
index 0000000..6eb57ea
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/clock/renovate.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": [
+ "local>lcobucci/.github:renovate-config"
+ ]
+}
diff --git a/api_candidatos/vendor/lcobucci/clock/src/Clock.php b/api_candidatos/vendor/lcobucci/clock/src/Clock.php
new file mode 100644
index 0000000..529a3c3
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/clock/src/Clock.php
@@ -0,0 +1,12 @@
+now = $now;
+ }
+
+ public function now(): DateTimeImmutable
+ {
+ return $this->now;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/clock/src/SystemClock.php b/api_candidatos/vendor/lcobucci/clock/src/SystemClock.php
new file mode 100644
index 0000000..69de81f
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/clock/src/SystemClock.php
@@ -0,0 +1,31 @@
+timezone);
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/LICENSE b/api_candidatos/vendor/lcobucci/jwt/LICENSE
new file mode 100644
index 0000000..cc7e28f
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014, Luís Cobucci
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/api_candidatos/vendor/lcobucci/jwt/composer.json b/api_candidatos/vendor/lcobucci/jwt/composer.json
new file mode 100644
index 0000000..b6788da
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/composer.json
@@ -0,0 +1,62 @@
+{
+ "name": "lcobucci/jwt",
+ "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+ "type": "library",
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "keywords": [
+ "JWT",
+ "JWS"
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "require": {
+ "php": "^7.4 || ^8.0",
+ "ext-mbstring": "*",
+ "ext-openssl": "*",
+ "lcobucci/clock": "^2.0"
+ },
+ "require-dev": {
+ "infection/infection": "^0.20",
+ "lcobucci/coding-standard": "^6.0",
+ "mikey179/vfsstream": "^1.6",
+ "phpbench/phpbench": "^0.17",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^0.12",
+ "phpstan/phpstan-deprecation-rules": "^0.12",
+ "phpstan/phpstan-phpunit": "^0.12",
+ "phpstan/phpstan-strict-rules": "^0.12",
+ "phpunit/php-invoker": "^3.1",
+ "phpunit/phpunit": "^9.4"
+ },
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\JWT\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Lcobucci\\JWT\\": [
+ "test/_keys",
+ "test/unit",
+ "test/performance"
+ ],
+ "Lcobucci\\JWT\\FunctionalTests\\": "test/functional"
+ }
+ },
+ "config": {
+ "preferred-install": "dist",
+ "sort-packages": true
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Builder.php b/api_candidatos/vendor/lcobucci/jwt/src/Builder.php
new file mode 100644
index 0000000..531e9d3
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Builder.php
@@ -0,0 +1,77 @@
+ $claims
+ *
+ * @return array
+ */
+ public function formatClaims(array $claims): array;
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Configuration.php b/api_candidatos/vendor/lcobucci/jwt/src/Configuration.php
new file mode 100644
index 0000000..8da1c8a
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Configuration.php
@@ -0,0 +1,154 @@
+signer = $signer;
+ $this->signingKey = $signingKey;
+ $this->verificationKey = $verificationKey;
+ $this->parser = new Token\Parser($decoder ?? new JoseEncoder());
+ $this->validator = new Validation\Validator();
+
+ $this->builderFactory = static function (ClaimsFormatter $claimFormatter) use ($encoder): Builder {
+ return new Token\Builder($encoder ?? new JoseEncoder(), $claimFormatter);
+ };
+ }
+
+ public static function forAsymmetricSigner(
+ Signer $signer,
+ Key $signingKey,
+ Key $verificationKey,
+ ?Encoder $encoder = null,
+ ?Decoder $decoder = null
+ ): self {
+ return new self(
+ $signer,
+ $signingKey,
+ $verificationKey,
+ $encoder,
+ $decoder
+ );
+ }
+
+ public static function forSymmetricSigner(
+ Signer $signer,
+ Key $key,
+ ?Encoder $encoder = null,
+ ?Decoder $decoder = null
+ ): self {
+ return new self(
+ $signer,
+ $key,
+ $key,
+ $encoder,
+ $decoder
+ );
+ }
+
+ public static function forUnsecuredSigner(
+ ?Encoder $encoder = null,
+ ?Decoder $decoder = null
+ ): self {
+ $key = InMemory::empty();
+
+ return new self(
+ new None(),
+ $key,
+ $key,
+ $encoder,
+ $decoder
+ );
+ }
+
+ /** @param callable(ClaimsFormatter): Builder $builderFactory */
+ public function setBuilderFactory(callable $builderFactory): void
+ {
+ $this->builderFactory = Closure::fromCallable($builderFactory);
+ }
+
+ public function builder(?ClaimsFormatter $claimFormatter = null): Builder
+ {
+ return ($this->builderFactory)($claimFormatter ?? ChainedFormatter::default());
+ }
+
+ public function parser(): Parser
+ {
+ return $this->parser;
+ }
+
+ public function setParser(Parser $parser): void
+ {
+ $this->parser = $parser;
+ }
+
+ public function signer(): Signer
+ {
+ return $this->signer;
+ }
+
+ public function signingKey(): Key
+ {
+ return $this->signingKey;
+ }
+
+ public function verificationKey(): Key
+ {
+ return $this->verificationKey;
+ }
+
+ public function validator(): Validator
+ {
+ return $this->validator;
+ }
+
+ public function setValidator(Validator $validator): void
+ {
+ $this->validator = $validator;
+ }
+
+ /** @return Constraint[] */
+ public function validationConstraints(): array
+ {
+ return $this->validationConstraints;
+ }
+
+ public function setValidationConstraints(Constraint ...$validationConstraints): void
+ {
+ $this->validationConstraints = $validationConstraints;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Decoder.php b/api_candidatos/vendor/lcobucci/jwt/src/Decoder.php
new file mode 100644
index 0000000..10fc991
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Decoder.php
@@ -0,0 +1,27 @@
+ */
+ private array $formatters;
+
+ public function __construct(ClaimsFormatter ...$formatters)
+ {
+ $this->formatters = $formatters;
+ }
+
+ public static function default(): self
+ {
+ return new self(new UnifyAudience(), new MicrosecondBasedDateConversion());
+ }
+
+ /** @inheritdoc */
+ public function formatClaims(array $claims): array
+ {
+ foreach ($this->formatters as $formatter) {
+ $claims = $formatter->formatClaims($claims);
+ }
+
+ return $claims;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php b/api_candidatos/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php
new file mode 100644
index 0000000..9cb49c4
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php
@@ -0,0 +1,65 @@
+convertDate($claims[$claim]);
+ }
+
+ return $claims;
+ }
+
+ /** @return int|float */
+ private function convertDate(DateTimeImmutable $date)
+ {
+ if ($date->format('u') === '000000') {
+ return (int) $date->format('U');
+ }
+
+ return (float) $date->format('U.u');
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php b/api_candidatos/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php
new file mode 100644
index 0000000..cf57252
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php
@@ -0,0 +1,29 @@
+converter = $converter;
+ }
+
+ public static function create(): Ecdsa
+ {
+ return new static(new MultibyteStringConverter()); // @phpstan-ignore-line
+ }
+
+ final public function sign(string $payload, Key $key): string
+ {
+ return $this->converter->fromAsn1(
+ $this->createSignature($key->contents(), $key->passphrase(), $payload),
+ $this->keyLength()
+ );
+ }
+
+ final public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return $this->verifySignature(
+ $this->converter->toAsn1($expected, $this->keyLength()),
+ $payload,
+ $key->contents()
+ );
+ }
+
+ final public function keyType(): int
+ {
+ return OPENSSL_KEYTYPE_EC;
+ }
+
+ /**
+ * Returns the length of each point in the signature, so that we can calculate and verify R and S points properly
+ *
+ * @internal
+ */
+ abstract public function keyLength(): int;
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php
new file mode 100644
index 0000000..d9ca751
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php
@@ -0,0 +1,25 @@
+ self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';
+
+ $asn1 = hex2bin(
+ self::ASN1_SEQUENCE
+ . $lengthPrefix . dechex($totalLength)
+ . self::ASN1_INTEGER . dechex($lengthR) . $pointR
+ . self::ASN1_INTEGER . dechex($lengthS) . $pointS
+ );
+ assert(is_string($asn1));
+
+ return $asn1;
+ }
+
+ private static function octetLength(string $data): int
+ {
+ return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE);
+ }
+
+ private static function preparePositiveInteger(string $data): string
+ {
+ if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
+ return self::ASN1_NEGATIVE_INTEGER . $data;
+ }
+
+ while (
+ mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
+ && mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT
+ ) {
+ $data = mb_substr($data, 2, null, '8bit');
+ }
+
+ return $data;
+ }
+
+ public function fromAsn1(string $signature, int $length): string
+ {
+ $message = bin2hex($signature);
+ $position = 0;
+
+ if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) {
+ throw ConversionFailed::incorrectStartSequence();
+ }
+
+ // @phpstan-ignore-next-line
+ if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) {
+ $position += self::BYTE_SIZE;
+ }
+
+ $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
+ $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
+
+ $points = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT));
+ assert(is_string($points));
+
+ return $points;
+ }
+
+ private static function readAsn1Content(string $message, int &$position, int $length): string
+ {
+ $content = mb_substr($message, $position, $length, '8bit');
+ $position += $length;
+
+ return $content;
+ }
+
+ private static function readAsn1Integer(string $message, int &$position): string
+ {
+ if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) {
+ throw ConversionFailed::integerExpected();
+ }
+
+ $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
+
+ return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
+ }
+
+ private static function retrievePositiveInteger(string $data): string
+ {
+ while (
+ mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
+ && mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT
+ ) {
+ $data = mb_substr($data, 2, null, '8bit');
+ }
+
+ return $data;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php
new file mode 100644
index 0000000..36f6ec1
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php
@@ -0,0 +1,26 @@
+algorithm(), $payload, $key->contents(), true);
+ }
+
+ final public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return hash_equals($expected, $this->sign($payload, $key));
+ }
+
+ abstract public function algorithm(): string;
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php
new file mode 100644
index 0000000..4be692e
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php
@@ -0,0 +1,19 @@
+contents = $contents;
+ $this->passphrase = $passphrase;
+ }
+
+ public static function empty(): self
+ {
+ return new self('', '');
+ }
+
+ public static function plainText(string $contents, string $passphrase = ''): self
+ {
+ return new self($contents, $passphrase);
+ }
+
+ public static function base64Encoded(string $contents, string $passphrase = ''): self
+ {
+ $decoded = base64_decode($contents, true);
+
+ if ($decoded === false) {
+ throw CannotDecodeContent::invalidBase64String();
+ }
+
+ return new self($decoded, $passphrase);
+ }
+
+ /** @throws FileCouldNotBeRead */
+ public static function file(string $path, string $passphrase = ''): self
+ {
+ try {
+ $file = new SplFileObject($path);
+ } catch (Throwable $exception) {
+ throw FileCouldNotBeRead::onPath($path, $exception);
+ }
+
+ $contents = $file->fread($file->getSize());
+ assert(is_string($contents));
+
+ return new self($contents, $passphrase);
+ }
+
+ public function contents(): string
+ {
+ return $this->contents;
+ }
+
+ public function passphrase(): string
+ {
+ return $this->passphrase;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/Key/LocalFileReference.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Key/LocalFileReference.php
new file mode 100644
index 0000000..b6cb3f1
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Key/LocalFileReference.php
@@ -0,0 +1,54 @@
+path = $path;
+ $this->passphrase = $passphrase;
+ }
+
+ /** @throws FileCouldNotBeRead */
+ public static function file(string $path, string $passphrase = ''): self
+ {
+ if (strpos($path, self::PATH_PREFIX) === 0) {
+ $path = substr($path, 7);
+ }
+
+ if (! file_exists($path)) {
+ throw FileCouldNotBeRead::onPath($path);
+ }
+
+ return new self($path, $passphrase);
+ }
+
+ public function contents(): string
+ {
+ if (! isset($this->contents)) {
+ $this->contents = InMemory::file($this->path)->contents();
+ }
+
+ return $this->contents;
+ }
+
+ public function passphrase(): string
+ {
+ return $this->passphrase;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/None.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/None.php
new file mode 100644
index 0000000..4e6ecb1
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/None.php
@@ -0,0 +1,26 @@
+getPrivateKey($pem, $passphrase);
+
+ try {
+ $signature = '';
+
+ if (! openssl_sign($payload, $signature, $key, $this->algorithm())) {
+ $error = openssl_error_string();
+ assert(is_string($error));
+
+ throw CannotSignPayload::errorHappened($error);
+ }
+
+ return $signature;
+ } finally {
+ $this->freeKey($key);
+ }
+ }
+
+ /**
+ * @return resource|OpenSSLAsymmetricKey
+ *
+ * @throws CannotSignPayload
+ */
+ private function getPrivateKey(string $pem, string $passphrase)
+ {
+ $privateKey = openssl_pkey_get_private($pem, $passphrase);
+ $this->validateKey($privateKey);
+
+ return $privateKey;
+ }
+
+ /** @throws InvalidKeyProvided */
+ final protected function verifySignature(
+ string $expected,
+ string $payload,
+ string $pem
+ ): bool {
+ $key = $this->getPublicKey($pem);
+ $result = openssl_verify($payload, $expected, $key, $this->algorithm());
+ $this->freeKey($key);
+
+ return $result === 1;
+ }
+
+ /**
+ * @return resource|OpenSSLAsymmetricKey
+ *
+ * @throws InvalidKeyProvided
+ */
+ private function getPublicKey(string $pem)
+ {
+ $publicKey = openssl_pkey_get_public($pem);
+ $this->validateKey($publicKey);
+
+ return $publicKey;
+ }
+
+ /**
+ * Raises an exception when the key type is not the expected type
+ *
+ * @param resource|OpenSSLAsymmetricKey|bool $key
+ *
+ * @throws InvalidKeyProvided
+ */
+ private function validateKey($key): void
+ {
+ if (is_bool($key)) {
+ $error = openssl_error_string();
+ assert(is_string($error));
+
+ throw InvalidKeyProvided::cannotBeParsed($error);
+ }
+
+ $details = openssl_pkey_get_details($key);
+ assert(is_array($details));
+
+ if (! array_key_exists('key', $details) || $details['type'] !== $this->keyType()) {
+ throw InvalidKeyProvided::incompatibleKey();
+ }
+ }
+
+ /** @param resource|OpenSSLAsymmetricKey $key */
+ private function freeKey($key): void
+ {
+ if ($key instanceof OpenSSLAsymmetricKey) {
+ return;
+ }
+
+ openssl_free_key($key); // Deprecated and no longer necessary as of PHP >= 8.0
+ }
+
+ /**
+ * Returns the type of key to be used to create/verify the signature (using OpenSSL constants)
+ *
+ * @internal
+ */
+ abstract public function keyType(): int;
+
+ /**
+ * Returns which algorithm to be used to create/verify the signature (using OpenSSL constants)
+ *
+ * @internal
+ */
+ abstract public function algorithm(): int;
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/Rsa.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Rsa.php
new file mode 100644
index 0000000..ff54dd3
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Rsa.php
@@ -0,0 +1,24 @@
+createSignature($key->contents(), $key->passphrase(), $payload);
+ }
+
+ final public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return $this->verifySignature($expected, $payload, $key->contents());
+ }
+
+ final public function keyType(): int
+ {
+ return OPENSSL_KEYTYPE_RSA;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php
new file mode 100644
index 0000000..9e56c70
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php
@@ -0,0 +1,21 @@
+ */
+ private array $headers = ['typ' => 'JWT', 'alg' => null];
+
+ /** @var array */
+ private array $claims = [];
+
+ private Encoder $encoder;
+ private ClaimsFormatter $claimFormatter;
+
+ public function __construct(Encoder $encoder, ClaimsFormatter $claimFormatter)
+ {
+ $this->encoder = $encoder;
+ $this->claimFormatter = $claimFormatter;
+ }
+
+ public function permittedFor(string ...$audiences): BuilderInterface
+ {
+ $configured = $this->claims[RegisteredClaims::AUDIENCE] ?? [];
+ $toAppend = array_diff($audiences, $configured);
+
+ return $this->setClaim(RegisteredClaims::AUDIENCE, array_merge($configured, $toAppend));
+ }
+
+ public function expiresAt(DateTimeImmutable $expiration): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::EXPIRATION_TIME, $expiration);
+ }
+
+ public function identifiedBy(string $id): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::ID, $id);
+ }
+
+ public function issuedAt(DateTimeImmutable $issuedAt): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::ISSUED_AT, $issuedAt);
+ }
+
+ public function issuedBy(string $issuer): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::ISSUER, $issuer);
+ }
+
+ public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::NOT_BEFORE, $notBefore);
+ }
+
+ public function relatedTo(string $subject): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::SUBJECT, $subject);
+ }
+
+ /** @inheritdoc */
+ public function withHeader(string $name, $value): BuilderInterface
+ {
+ $this->headers[$name] = $value;
+
+ return $this;
+ }
+
+ /** @inheritdoc */
+ public function withClaim(string $name, $value): BuilderInterface
+ {
+ if (in_array($name, RegisteredClaims::ALL, true)) {
+ throw RegisteredClaimGiven::forClaim($name);
+ }
+
+ return $this->setClaim($name, $value);
+ }
+
+ /** @param mixed $value */
+ private function setClaim(string $name, $value): BuilderInterface
+ {
+ $this->claims[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @param array $items
+ *
+ * @throws CannotEncodeContent When data cannot be converted to JSON.
+ */
+ private function encode(array $items): string
+ {
+ return $this->encoder->base64UrlEncode(
+ $this->encoder->jsonEncode($items)
+ );
+ }
+
+ public function getToken(Signer $signer, Key $key): Plain
+ {
+ $headers = $this->headers;
+ $headers['alg'] = $signer->algorithmId();
+
+ $encodedHeaders = $this->encode($headers);
+ $encodedClaims = $this->encode($this->claimFormatter->formatClaims($this->claims));
+
+ $signature = $signer->sign($encodedHeaders . '.' . $encodedClaims, $key);
+ $encodedSignature = $this->encoder->base64UrlEncode($signature);
+
+ return new Plain(
+ new DataSet($headers, $encodedHeaders),
+ new DataSet($this->claims, $encodedClaims),
+ new Signature($signature, $encodedSignature)
+ );
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Token/DataSet.php b/api_candidatos/vendor/lcobucci/jwt/src/Token/DataSet.php
new file mode 100644
index 0000000..f9256d6
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Token/DataSet.php
@@ -0,0 +1,46 @@
+ */
+ private array $data;
+ private string $encoded;
+
+ /** @param mixed[] $data */
+ public function __construct(array $data, string $encoded)
+ {
+ $this->data = $data;
+ $this->encoded = $encoded;
+ }
+
+ /**
+ * @param mixed|null $default
+ *
+ * @return mixed|null
+ */
+ public function get(string $name, $default = null)
+ {
+ return $this->data[$name] ?? $default;
+ }
+
+ public function has(string $name): bool
+ {
+ return array_key_exists($name, $this->data);
+ }
+
+ /** @return mixed[] */
+ public function all(): array
+ {
+ return $this->data;
+ }
+
+ public function toString(): string
+ {
+ return $this->encoded;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php b/api_candidatos/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php
new file mode 100644
index 0000000..49c2840
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php
@@ -0,0 +1,25 @@
+decoder = $decoder;
+ }
+
+ public function parse(string $jwt): TokenInterface
+ {
+ [$encodedHeaders, $encodedClaims, $encodedSignature] = $this->splitJwt($jwt);
+
+ $header = $this->parseHeader($encodedHeaders);
+
+ return new Plain(
+ new DataSet($header, $encodedHeaders),
+ new DataSet($this->parseClaims($encodedClaims), $encodedClaims),
+ $this->parseSignature($header, $encodedSignature)
+ );
+ }
+
+ /**
+ * Splits the JWT string into an array
+ *
+ * @return string[]
+ *
+ * @throws InvalidTokenStructure When JWT doesn't have all parts.
+ */
+ private function splitJwt(string $jwt): array
+ {
+ $data = explode('.', $jwt);
+
+ if (count($data) !== 3) {
+ throw InvalidTokenStructure::missingOrNotEnoughSeparators();
+ }
+
+ return $data;
+ }
+
+ /**
+ * Parses the header from a string
+ *
+ * @return mixed[]
+ *
+ * @throws UnsupportedHeaderFound When an invalid header is informed.
+ * @throws InvalidTokenStructure When parsed content isn't an array.
+ */
+ private function parseHeader(string $data): array
+ {
+ $header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
+
+ if (! is_array($header)) {
+ throw InvalidTokenStructure::arrayExpected('headers');
+ }
+
+ if (array_key_exists('enc', $header)) {
+ throw UnsupportedHeaderFound::encryption();
+ }
+
+ if (! array_key_exists('typ', $header)) {
+ $header['typ'] = 'JWT';
+ }
+
+ return $header;
+ }
+
+ /**
+ * Parses the claim set from a string
+ *
+ * @return mixed[]
+ *
+ * @throws InvalidTokenStructure When parsed content isn't an array or contains non-parseable dates.
+ */
+ private function parseClaims(string $data): array
+ {
+ $claims = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
+
+ if (! is_array($claims)) {
+ throw InvalidTokenStructure::arrayExpected('claims');
+ }
+
+ if (array_key_exists(RegisteredClaims::AUDIENCE, $claims)) {
+ $claims[RegisteredClaims::AUDIENCE] = (array) $claims[RegisteredClaims::AUDIENCE];
+ }
+
+ foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
+ if (! array_key_exists($claim, $claims)) {
+ continue;
+ }
+
+ $claims[$claim] = $this->convertDate($claims[$claim]);
+ }
+
+ return $claims;
+ }
+
+ /**
+ * @param int|float|string $timestamp
+ *
+ * @throws InvalidTokenStructure
+ */
+ private function convertDate($timestamp): DateTimeImmutable
+ {
+ if (! is_numeric($timestamp)) {
+ throw InvalidTokenStructure::dateIsNotParseable($timestamp);
+ }
+
+ $normalizedTimestamp = number_format((float) $timestamp, self::MICROSECOND_PRECISION, '.', '');
+
+ $date = DateTimeImmutable::createFromFormat('U.u', $normalizedTimestamp);
+
+ if ($date === false) {
+ throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp);
+ }
+
+ return $date;
+ }
+
+ /**
+ * Returns the signature from given data
+ *
+ * @param mixed[] $header
+ */
+ private function parseSignature(array $header, string $data): Signature
+ {
+ if ($data === '' || ! array_key_exists('alg', $header) || $header['alg'] === 'none') {
+ return Signature::fromEmptyData();
+ }
+
+ $hash = $this->decoder->base64UrlDecode($data);
+
+ return new Signature($hash, $data);
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Token/Plain.php b/api_candidatos/vendor/lcobucci/jwt/src/Token/Plain.php
new file mode 100644
index 0000000..1a7b4cd
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Token/Plain.php
@@ -0,0 +1,92 @@
+headers = $headers;
+ $this->claims = $claims;
+ $this->signature = $signature;
+ }
+
+ public function headers(): DataSet
+ {
+ return $this->headers;
+ }
+
+ public function claims(): DataSet
+ {
+ return $this->claims;
+ }
+
+ public function signature(): Signature
+ {
+ return $this->signature;
+ }
+
+ public function payload(): string
+ {
+ return $this->headers->toString() . '.' . $this->claims->toString();
+ }
+
+ public function isPermittedFor(string $audience): bool
+ {
+ return in_array($audience, $this->claims->get(RegisteredClaims::AUDIENCE, []), true);
+ }
+
+ public function isIdentifiedBy(string $id): bool
+ {
+ return $this->claims->get(RegisteredClaims::ID) === $id;
+ }
+
+ public function isRelatedTo(string $subject): bool
+ {
+ return $this->claims->get(RegisteredClaims::SUBJECT) === $subject;
+ }
+
+ public function hasBeenIssuedBy(string ...$issuers): bool
+ {
+ return in_array($this->claims->get(RegisteredClaims::ISSUER), $issuers, true);
+ }
+
+ public function hasBeenIssuedBefore(DateTimeInterface $now): bool
+ {
+ return $now >= $this->claims->get(RegisteredClaims::ISSUED_AT);
+ }
+
+ public function isMinimumTimeBefore(DateTimeInterface $now): bool
+ {
+ return $now >= $this->claims->get(RegisteredClaims::NOT_BEFORE);
+ }
+
+ public function isExpired(DateTimeInterface $now): bool
+ {
+ if (! $this->claims->has(RegisteredClaims::EXPIRATION_TIME)) {
+ return false;
+ }
+
+ return $now >= $this->claims->get(RegisteredClaims::EXPIRATION_TIME);
+ }
+
+ public function toString(): string
+ {
+ return $this->headers->toString() . '.'
+ . $this->claims->toString() . '.'
+ . $this->signature->toString();
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php b/api_candidatos/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php
new file mode 100644
index 0000000..e70996e
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php
@@ -0,0 +1,20 @@
+hash = $hash;
+ $this->encoded = $encoded;
+ }
+
+ public static function fromEmptyData(): self
+ {
+ return new self('', '');
+ }
+
+ public function hash(): string
+ {
+ return $this->hash;
+ }
+
+ /**
+ * Returns the encoded version of the signature
+ */
+ public function toString(): string
+ {
+ return $this->encoded;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php b/api_candidatos/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php
new file mode 100644
index 0000000..1824078
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php
@@ -0,0 +1,15 @@
+id = $id;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token->isIdentifiedBy($this->id)) {
+ throw new ConstraintViolation(
+ 'The token is not identified with the expected ID'
+ );
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php
new file mode 100644
index 0000000..5f5346e
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php
@@ -0,0 +1,28 @@
+issuers = $issuers;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token->hasBeenIssuedBy(...$this->issuers)) {
+ throw new ConstraintViolation(
+ 'The token was not issued by the given issuers'
+ );
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php
new file mode 100644
index 0000000..53abc0d
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php
@@ -0,0 +1,15 @@
+audience = $audience;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token->isPermittedFor($this->audience)) {
+ throw new ConstraintViolation(
+ 'The token is not allowed to be used by this audience'
+ );
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php
new file mode 100644
index 0000000..8beecd7
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php
@@ -0,0 +1,27 @@
+subject = $subject;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token->isRelatedTo($this->subject)) {
+ throw new ConstraintViolation(
+ 'The token is not related to the expected subject'
+ );
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php
new file mode 100644
index 0000000..56acb2e
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php
@@ -0,0 +1,36 @@
+signer = $signer;
+ $this->key = $key;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token instanceof Token\Plain) {
+ throw new ConstraintViolation('You should pass a plain token');
+ }
+
+ if ($token->headers()->get('alg') !== $this->signer->algorithmId()) {
+ throw new ConstraintViolation('Token signer mismatch');
+ }
+
+ if (! $this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) {
+ throw new ConstraintViolation('Token signature mismatch');
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/ValidAt.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/ValidAt.php
new file mode 100644
index 0000000..6186686
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Constraint/ValidAt.php
@@ -0,0 +1,69 @@
+clock = $clock;
+ $this->leeway = $this->guardLeeway($leeway);
+ }
+
+ private function guardLeeway(?DateInterval $leeway): DateInterval
+ {
+ if ($leeway === null) {
+ return new DateInterval('PT0S');
+ }
+
+ if ($leeway->invert === 1) {
+ throw LeewayCannotBeNegative::create();
+ }
+
+ return $leeway;
+ }
+
+ public function assert(Token $token): void
+ {
+ $now = $this->clock->now();
+
+ $this->assertIssueTime($token, $now->add($this->leeway));
+ $this->assertMinimumTime($token, $now->add($this->leeway));
+ $this->assertExpiration($token, $now->sub($this->leeway));
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertExpiration(Token $token, DateTimeInterface $now): void
+ {
+ if ($token->isExpired($now)) {
+ throw new ConstraintViolation('The token is expired');
+ }
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertMinimumTime(Token $token, DateTimeInterface $now): void
+ {
+ if (! $token->isMinimumTimeBefore($now)) {
+ throw new ConstraintViolation('The token cannot be used yet');
+ }
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertIssueTime(Token $token, DateTimeInterface $now): void
+ {
+ if (! $token->hasBeenIssuedBefore($now)) {
+ throw new ConstraintViolation('The token was issued in the future');
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php
new file mode 100644
index 0000000..39a56ed
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php
@@ -0,0 +1,11 @@
+violations = $violations;
+
+ return $exception;
+ }
+
+ /** @param ConstraintViolation[] $violations */
+ private static function buildMessage(array $violations): string
+ {
+ $violations = array_map(
+ static function (ConstraintViolation $violation): string {
+ return '- ' . $violation->getMessage();
+ },
+ $violations
+ );
+
+ $message = "The token violates some mandatory constraints, details:\n";
+ $message .= implode("\n", $violations);
+
+ return $message;
+ }
+
+ /** @return ConstraintViolation[] */
+ public function violations(): array
+ {
+ return $this->violations;
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validation/Validator.php b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Validator.php
new file mode 100644
index 0000000..62d0618
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validation/Validator.php
@@ -0,0 +1,56 @@
+checkConstraint($constraint, $token, $violations);
+ }
+
+ if ($violations) {
+ throw RequiredConstraintsViolated::fromViolations(...$violations);
+ }
+ }
+
+ /** @param ConstraintViolation[] $violations */
+ private function checkConstraint(
+ Constraint $constraint,
+ Token $token,
+ array &$violations
+ ): void {
+ try {
+ $constraint->assert($token);
+ } catch (ConstraintViolation $e) {
+ $violations[] = $e;
+ }
+ }
+
+ public function validate(Token $token, Constraint ...$constraints): bool
+ {
+ if ($constraints === []) {
+ throw new NoConstraintsGiven('No constraint given.');
+ }
+
+ try {
+ foreach ($constraints as $constraint) {
+ $constraint->assert($token);
+ }
+
+ return true;
+ } catch (ConstraintViolation $e) {
+ return false;
+ }
+ }
+}
diff --git a/api_candidatos/vendor/lcobucci/jwt/src/Validator.php b/api_candidatos/vendor/lcobucci/jwt/src/Validator.php
new file mode 100644
index 0000000..d0ce4b8
--- /dev/null
+++ b/api_candidatos/vendor/lcobucci/jwt/src/Validator.php
@@ -0,0 +1,20 @@
+=7.1.0"
+ },
+ "require-dev": {
+ "henrikbjorn/phpspec-code-coverage": "~1.0.1",
+ "phpspec/phpspec": "^2.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Event\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "League\\Event\\Stub\\": "stubs/"
+ }
+ },
+ "config": {
+ "bin-dir": "bin"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/AbstractEvent.php b/api_candidatos/vendor/league/event/src/AbstractEvent.php
new file mode 100644
index 0000000..dab2f58
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/AbstractEvent.php
@@ -0,0 +1,64 @@
+emitter = $emitter;
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getEmitter()
+ {
+ return $this->emitter;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function stopPropagation()
+ {
+ $this->propagationStopped = true;
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function isPropagationStopped()
+ {
+ return $this->propagationStopped;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return get_class($this);
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/AbstractListener.php b/api_candidatos/vendor/league/event/src/AbstractListener.php
new file mode 100644
index 0000000..95077a0
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/AbstractListener.php
@@ -0,0 +1,14 @@
+bufferedEvents[] = $event;
+
+ return $event;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function emitBatch(array $events)
+ {
+ foreach ($events as $event) {
+ $this->bufferedEvents[] = $event;
+ }
+
+ return $events;
+ }
+
+ /**
+ * Emit the buffered events.
+ *
+ * @return array
+ */
+ public function emitBufferedEvents()
+ {
+ $result = [];
+
+ while ($event = array_shift($this->bufferedEvents)) {
+ $result[] = parent::emit($event);
+ }
+
+ return $result;
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/CallbackListener.php b/api_candidatos/vendor/league/event/src/CallbackListener.php
new file mode 100644
index 0000000..31eb589
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/CallbackListener.php
@@ -0,0 +1,65 @@
+callback = $callback;
+ }
+
+ /**
+ * Get the callback.
+ *
+ * @return callable
+ */
+ public function getCallback()
+ {
+ return $this->callback;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function handle(EventInterface $event)
+ {
+ call_user_func_array($this->callback, func_get_args());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function isListener($listener)
+ {
+ if ($listener instanceof CallbackListener) {
+ $listener = $listener->getCallback();
+ }
+
+ return $this->callback === $listener;
+ }
+
+ /**
+ * Named constructor
+ *
+ * @param callable $callable
+ *
+ * @return static
+ */
+ public static function fromCallable(callable $callable)
+ {
+ return new static($callable);
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/Emitter.php b/api_candidatos/vendor/league/event/src/Emitter.php
new file mode 100644
index 0000000..1cfe7b4
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/Emitter.php
@@ -0,0 +1,268 @@
+ensureListener($listener);
+ $this->listeners[$event][$priority][] = $listener;
+ $this->clearSortedListeners($event);
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function addOneTimeListener($event, $listener, $priority = self::P_NORMAL)
+ {
+ $listener = $this->ensureListener($listener);
+ $listener = new OneTimeListener($listener);
+
+ return $this->addListener($event, $listener, $priority);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function useListenerProvider(ListenerProviderInterface $provider)
+ {
+ $acceptor = new ListenerAcceptor($this);
+ $provider->provideListeners($acceptor);
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function removeListener($event, $listener)
+ {
+ $this->clearSortedListeners($event);
+ $listeners = $this->hasListeners($event)
+ ? $this->listeners[$event]
+ : [];
+
+ $filter = function ($registered) use ($listener) {
+ return ! $registered->isListener($listener);
+ };
+
+ foreach ($listeners as $priority => $collection) {
+ $listeners[$priority] = array_filter($collection, $filter);
+ }
+
+ $this->listeners[$event] = $listeners;
+
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function removeAllListeners($event)
+ {
+ $this->clearSortedListeners($event);
+
+ if ($this->hasListeners($event)) {
+ unset($this->listeners[$event]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Ensure the input is a listener.
+ *
+ * @param ListenerInterface|callable $listener
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return ListenerInterface
+ */
+ protected function ensureListener($listener)
+ {
+ if ($listener instanceof ListenerInterface) {
+ return $listener;
+ }
+
+ if (is_callable($listener)) {
+ return CallbackListener::fromCallable($listener);
+ }
+
+ throw new InvalidArgumentException('Listeners should be ListenerInterface, Closure or callable. Received type: '.gettype($listener));
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function hasListeners($event)
+ {
+ if (! isset($this->listeners[$event]) || count($this->listeners[$event]) === 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getListeners($event)
+ {
+ if (array_key_exists($event, $this->sortedListeners)) {
+ return $this->sortedListeners[$event];
+ }
+
+ return $this->sortedListeners[$event] = $this->getSortedListeners($event);
+ }
+
+ /**
+ * Get the listeners sorted by priority for a given event.
+ *
+ * @param string $event
+ *
+ * @return ListenerInterface[]
+ */
+ protected function getSortedListeners($event)
+ {
+ if (! $this->hasListeners($event)) {
+ return [];
+ }
+
+ $listeners = $this->listeners[$event];
+ krsort($listeners);
+
+ return call_user_func_array('array_merge', $listeners);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function emit($event)
+ {
+ list($name, $event) = $this->prepareEvent($event);
+ $arguments = [$event] + func_get_args();
+ $this->invokeListeners($name, $event, $arguments);
+ $this->invokeListeners('*', $event, $arguments);
+
+ return $event;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function emitBatch(array $events)
+ {
+ $results = [];
+
+ foreach ($events as $event) {
+ $results[] = $this->emit($event);
+ }
+
+ return $results;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function emitGeneratedEvents(GeneratorInterface $generator)
+ {
+ $events = $generator->releaseEvents();
+
+ return $this->emitBatch($events);
+ }
+
+ /**
+ * Invoke the listeners for an event.
+ *
+ * @param string $name
+ * @param EventInterface $event
+ * @param array $arguments
+ *
+ * @return void
+ */
+ protected function invokeListeners($name, EventInterface $event, array $arguments)
+ {
+ $listeners = $this->getListeners($name);
+
+ foreach ($listeners as $listener) {
+ if ($event->isPropagationStopped()) {
+ break;
+ }
+
+ call_user_func_array([$listener, 'handle'], $arguments);
+ }
+ }
+
+ /**
+ * Prepare an event for emitting.
+ *
+ * @param string|EventInterface $event
+ *
+ * @return array
+ */
+ protected function prepareEvent($event)
+ {
+ $event = $this->ensureEvent($event);
+ $name = $event->getName();
+ $event->setEmitter($this);
+
+ return [$name, $event];
+ }
+
+ /**
+ * Ensure event input is of type EventInterface or convert it.
+ *
+ * @param string|EventInterface $event
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return EventInterface
+ */
+ protected function ensureEvent($event)
+ {
+ if (is_string($event)) {
+ return Event::named($event);
+ }
+
+ if (! $event instanceof EventInterface) {
+ throw new InvalidArgumentException('Events should be provides as Event instances or string, received type: '.gettype($event));
+ }
+
+ return $event;
+ }
+
+ /**
+ * Clear the sorted listeners for an event
+ *
+ * @param $event
+ */
+ protected function clearSortedListeners($event)
+ {
+ unset($this->sortedListeners[$event]);
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/EmitterAwareInterface.php b/api_candidatos/vendor/league/event/src/EmitterAwareInterface.php
new file mode 100644
index 0000000..59ade45
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/EmitterAwareInterface.php
@@ -0,0 +1,22 @@
+emitter = $emitter;
+
+ return $this;
+ }
+
+ /**
+ * Get the Emitter.
+ *
+ * @return EmitterInterface
+ */
+ public function getEmitter()
+ {
+ if (! $this->emitter) {
+ $this->emitter = new Emitter();
+ }
+
+ return $this->emitter;
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/EmitterInterface.php b/api_candidatos/vendor/league/event/src/EmitterInterface.php
new file mode 100644
index 0000000..4f0fded
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/EmitterInterface.php
@@ -0,0 +1,92 @@
+getEmitter()->addListener($event, $listener, $priority);
+
+ return $this;
+ }
+
+ /**
+ * Add a one time listener for an event.
+ *
+ * The first parameter should be the event name, and the second should be
+ * the event listener. It may implement the League\Event\ListenerInterface
+ * or simply be "callable".
+ *
+ * @param string $event
+ * @param ListenerInterface|callable $listener
+ * @param int $priority
+ *
+ * @return $this
+ */
+ public function addOneTimeListener($event, $listener, $priority = ListenerAcceptorInterface::P_NORMAL)
+ {
+ $this->getEmitter()->addOneTimeListener($event, $listener, $priority);
+
+ return $this;
+ }
+
+ /**
+ * Remove a specific listener for an event.
+ *
+ * The first parameter should be the event name, and the second should be
+ * the event listener. It may implement the League\Event\ListenerInterface
+ * or simply be "callable".
+ *
+ * @param string $event
+ * @param ListenerInterface|callable $listener
+ *
+ * @return $this
+ */
+ public function removeListener($event, $listener)
+ {
+ $this->getEmitter()->removeListener($event, $listener);
+
+ return $this;
+ }
+
+ /**
+ * Remove all listeners for an event.
+ *
+ * The first parameter should be the event name. All event listeners will
+ * be removed.
+ *
+ * @param string $event
+ *
+ * @return $this
+ */
+ public function removeAllListeners($event)
+ {
+ $this->getEmitter()->removeAllListeners($event);
+
+ return $this;
+ }
+
+ /**
+ * Add listeners from a provider.
+ *
+ * @param ListenerProviderInterface $provider
+ *
+ * @return $this
+ */
+ public function useListenerProvider(ListenerProviderInterface $provider)
+ {
+ $this->getEmitter()->useListenerProvider($provider);
+
+ return $this;
+ }
+
+ /**
+ * Emit an event.
+ *
+ * @param string|EventInterface $event
+ *
+ * @return EventInterface
+ */
+ public function emit($event)
+ {
+ $emitter = $this->getEmitter();
+ $arguments = [$event] + func_get_args();
+
+ return call_user_func_array([$emitter, 'emit'], $arguments);
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/Event.php b/api_candidatos/vendor/league/event/src/Event.php
new file mode 100644
index 0000000..826b00a
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/Event.php
@@ -0,0 +1,43 @@
+name = $name;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Create a new event instance.
+ *
+ * @param string $name
+ *
+ * @return static
+ */
+ public static function named($name)
+ {
+ return new static($name);
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/EventInterface.php b/api_candidatos/vendor/league/event/src/EventInterface.php
new file mode 100644
index 0000000..84f2972
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/EventInterface.php
@@ -0,0 +1,43 @@
+events[] = $event;
+
+ return $this;
+ }
+
+ /**
+ * Release all the added events.
+ *
+ * @return EventInterface[]
+ */
+ public function releaseEvents()
+ {
+ $events = $this->events;
+ $this->events = [];
+
+ return $events;
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/ListenerAcceptor.php b/api_candidatos/vendor/league/event/src/ListenerAcceptor.php
new file mode 100644
index 0000000..259b86d
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/ListenerAcceptor.php
@@ -0,0 +1,43 @@
+emitter = $emitter;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function addListener($event, $listener, $priority = self::P_NORMAL)
+ {
+ $this->emitter->addListener($event, $listener, $priority);
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function addOneTimeListener($event, $listener, $priority = self::P_NORMAL)
+ {
+ $this->emitter->addOneTimeListener($event, $listener, $priority);
+
+ return $this;
+ }
+}
diff --git a/api_candidatos/vendor/league/event/src/ListenerAcceptorInterface.php b/api_candidatos/vendor/league/event/src/ListenerAcceptorInterface.php
new file mode 100644
index 0000000..758c273
--- /dev/null
+++ b/api_candidatos/vendor/league/event/src/ListenerAcceptorInterface.php
@@ -0,0 +1,59 @@
+listener = $listener;
+ }
+
+ /**
+ * Get the wrapped listener.
+ *
+ * @return ListenerInterface
+ */
+ public function getWrappedListener()
+ {
+ return $this->listener;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function handle(EventInterface $event)
+ {
+ $name = $event->getName();
+ $emitter = $event->getEmitter();
+ $emitter->removeListener($name, $this->listener);
+
+ return call_user_func_array([$this->listener, 'handle'], func_get_args());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function isListener($listener)
+ {
+ if ($listener instanceof OneTimeListener) {
+ $listener = $listener->getWrappedListener();
+ }
+
+ return $this->listener->isListener($listener);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/LICENSE b/api_candidatos/vendor/league/oauth2-server/LICENSE
new file mode 100644
index 0000000..a4f444b
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/LICENSE
@@ -0,0 +1,20 @@
+MIT License
+
+Copyright (C) Alex Bilbie
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/api_candidatos/vendor/league/oauth2-server/composer.json b/api_candidatos/vendor/league/oauth2-server/composer.json
new file mode 100644
index 0000000..593f75a
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/composer.json
@@ -0,0 +1,73 @@
+{
+ "name": "league/oauth2-server",
+ "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
+ "homepage": "https://oauth2.thephpleague.com/",
+ "license": "MIT",
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "ext-openssl": "*",
+ "league/event": "^2.2",
+ "league/uri": "^6.4",
+ "lcobucci/jwt": "^3.4.6 || ^4.0.4",
+ "psr/http-message": "^1.0.1",
+ "defuse/php-encryption": "^2.2.1",
+ "ext-json": "*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5.13",
+ "laminas/laminas-diactoros": "^2.4.1",
+ "phpstan/phpstan": "^0.12.57",
+ "phpstan/phpstan-phpunit": "^0.12.16",
+ "roave/security-advisories": "dev-master"
+ },
+ "repositories": [
+ {
+ "type": "git",
+ "url": "https://github.com/thephpleague/oauth2-server.git"
+ }
+ ],
+ "keywords": [
+ "oauth",
+ "oauth2",
+ "oauth 2",
+ "oauth 2.0",
+ "server",
+ "auth",
+ "authorization",
+ "authorisation",
+ "authentication",
+ "resource",
+ "api",
+ "auth",
+ "protect",
+ "secure"
+ ],
+ "authors": [
+ {
+ "name": "Alex Bilbie",
+ "email": "hello@alexbilbie.com",
+ "homepage": "http://www.alexbilbie.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Andy Millington",
+ "email": "andrew@noexceptions.io",
+ "homepage": "https://www.noexceptions.io",
+ "role": "Developer"
+ }
+ ],
+ "replace": {
+ "lncd/oauth2": "*",
+ "league/oauth2server": "*"
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\OAuth2\\Server\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "LeagueTests\\": "tests/"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/AuthorizationServer.php b/api_candidatos/vendor/league/oauth2-server/src/AuthorizationServer.php
new file mode 100644
index 0000000..5e6841f
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/AuthorizationServer.php
@@ -0,0 +1,252 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use DateInterval;
+use Defuse\Crypto\Key;
+use League\Event\EmitterAwareInterface;
+use League\Event\EmitterAwareTrait;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Grant\GrantTypeInterface;
+use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
+use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
+use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
+use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
+use League\OAuth2\Server\ResponseTypes\AbstractResponseType;
+use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class AuthorizationServer implements EmitterAwareInterface
+{
+ use EmitterAwareTrait;
+
+ /**
+ * @var GrantTypeInterface[]
+ */
+ protected $enabledGrantTypes = [];
+
+ /**
+ * @var DateInterval[]
+ */
+ protected $grantTypeAccessTokenTTL = [];
+
+ /**
+ * @var CryptKey
+ */
+ protected $privateKey;
+
+ /**
+ * @var CryptKey
+ */
+ protected $publicKey;
+
+ /**
+ * @var ResponseTypeInterface
+ */
+ protected $responseType;
+
+ /**
+ * @var ClientRepositoryInterface
+ */
+ private $clientRepository;
+
+ /**
+ * @var AccessTokenRepositoryInterface
+ */
+ private $accessTokenRepository;
+
+ /**
+ * @var ScopeRepositoryInterface
+ */
+ private $scopeRepository;
+
+ /**
+ * @var string|Key
+ */
+ private $encryptionKey;
+
+ /**
+ * @var string
+ */
+ private $defaultScope = '';
+
+ /**
+ * @var bool
+ */
+ private $revokeRefreshTokens = true;
+
+ /**
+ * New server instance.
+ *
+ * @param ClientRepositoryInterface $clientRepository
+ * @param AccessTokenRepositoryInterface $accessTokenRepository
+ * @param ScopeRepositoryInterface $scopeRepository
+ * @param CryptKey|string $privateKey
+ * @param string|Key $encryptionKey
+ * @param null|ResponseTypeInterface $responseType
+ */
+ public function __construct(
+ ClientRepositoryInterface $clientRepository,
+ AccessTokenRepositoryInterface $accessTokenRepository,
+ ScopeRepositoryInterface $scopeRepository,
+ $privateKey,
+ $encryptionKey,
+ ?ResponseTypeInterface $responseType = null
+ ) {
+ $this->clientRepository = $clientRepository;
+ $this->accessTokenRepository = $accessTokenRepository;
+ $this->scopeRepository = $scopeRepository;
+
+ if ($privateKey instanceof CryptKey === false) {
+ $privateKey = new CryptKey($privateKey);
+ }
+
+ $this->privateKey = $privateKey;
+ $this->encryptionKey = $encryptionKey;
+
+ if ($responseType === null) {
+ $responseType = new BearerTokenResponse();
+ } else {
+ $responseType = clone $responseType;
+ }
+
+ $this->responseType = $responseType;
+ }
+
+ /**
+ * Enable a grant type on the server.
+ *
+ * @param GrantTypeInterface $grantType
+ * @param null|DateInterval $accessTokenTTL
+ */
+ public function enableGrantType(GrantTypeInterface $grantType, ?DateInterval $accessTokenTTL = null)
+ {
+ if ($accessTokenTTL === null) {
+ $accessTokenTTL = new DateInterval('PT1H');
+ }
+
+ $grantType->setAccessTokenRepository($this->accessTokenRepository);
+ $grantType->setClientRepository($this->clientRepository);
+ $grantType->setScopeRepository($this->scopeRepository);
+ $grantType->setDefaultScope($this->defaultScope);
+ $grantType->setPrivateKey($this->privateKey);
+ $grantType->setEmitter($this->getEmitter());
+ $grantType->setEncryptionKey($this->encryptionKey);
+ $grantType->revokeRefreshTokens($this->revokeRefreshTokens);
+
+ $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
+ $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
+ }
+
+ /**
+ * Validate an authorization request
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @throws OAuthServerException
+ *
+ * @return AuthorizationRequest
+ */
+ public function validateAuthorizationRequest(ServerRequestInterface $request)
+ {
+ foreach ($this->enabledGrantTypes as $grantType) {
+ if ($grantType->canRespondToAuthorizationRequest($request)) {
+ return $grantType->validateAuthorizationRequest($request);
+ }
+ }
+
+ throw OAuthServerException::unsupportedGrantType();
+ }
+
+ /**
+ * Complete an authorization request
+ *
+ * @param AuthorizationRequest $authRequest
+ * @param ResponseInterface $response
+ *
+ * @return ResponseInterface
+ */
+ public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response)
+ {
+ return $this->enabledGrantTypes[$authRequest->getGrantTypeId()]
+ ->completeAuthorizationRequest($authRequest)
+ ->generateHttpResponse($response);
+ }
+
+ /**
+ * Return an access token response.
+ *
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ *
+ * @throws OAuthServerException
+ *
+ * @return ResponseInterface
+ */
+ public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
+ {
+ foreach ($this->enabledGrantTypes as $grantType) {
+ if (!$grantType->canRespondToAccessTokenRequest($request)) {
+ continue;
+ }
+ $tokenResponse = $grantType->respondToAccessTokenRequest(
+ $request,
+ $this->getResponseType(),
+ $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()]
+ );
+
+ if ($tokenResponse instanceof ResponseTypeInterface) {
+ return $tokenResponse->generateHttpResponse($response);
+ }
+ }
+
+ throw OAuthServerException::unsupportedGrantType();
+ }
+
+ /**
+ * Get the token type that grants will return in the HTTP response.
+ *
+ * @return ResponseTypeInterface
+ */
+ protected function getResponseType()
+ {
+ $responseType = clone $this->responseType;
+
+ if ($responseType instanceof AbstractResponseType) {
+ $responseType->setPrivateKey($this->privateKey);
+ }
+
+ $responseType->setEncryptionKey($this->encryptionKey);
+
+ return $responseType;
+ }
+
+ /**
+ * Set the default scope for the authorization server.
+ *
+ * @param string $defaultScope
+ */
+ public function setDefaultScope($defaultScope)
+ {
+ $this->defaultScope = $defaultScope;
+ }
+
+ /**
+ * Sets whether to revoke refresh tokens or not (for all grant types).
+ *
+ * @param bool $revokeRefreshTokens
+ */
+ public function revokeRefreshTokens(bool $revokeRefreshTokens): void
+ {
+ $this->revokeRefreshTokens = $revokeRefreshTokens;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/AuthorizationValidators/AuthorizationValidatorInterface.php b/api_candidatos/vendor/league/oauth2-server/src/AuthorizationValidators/AuthorizationValidatorInterface.php
new file mode 100644
index 0000000..7e49f84
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/AuthorizationValidators/AuthorizationValidatorInterface.php
@@ -0,0 +1,25 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\AuthorizationValidators;
+
+use Psr\Http\Message\ServerRequestInterface;
+
+interface AuthorizationValidatorInterface
+{
+ /**
+ * Determine the access token in the authorization header and append OAUth properties to the request
+ * as attributes.
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @return ServerRequestInterface
+ */
+ public function validateAuthorization(ServerRequestInterface $request);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/AuthorizationValidators/BearerTokenValidator.php b/api_candidatos/vendor/league/oauth2-server/src/AuthorizationValidators/BearerTokenValidator.php
new file mode 100644
index 0000000..ae99e0f
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/AuthorizationValidators/BearerTokenValidator.php
@@ -0,0 +1,148 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\AuthorizationValidators;
+
+use DateTimeZone;
+use Lcobucci\Clock\SystemClock;
+use Lcobucci\JWT\Configuration;
+use Lcobucci\JWT\Signer\Key\InMemory;
+use Lcobucci\JWT\Signer\Rsa\Sha256;
+use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
+use Lcobucci\JWT\Validation\Constraint\SignedWith;
+use Lcobucci\JWT\Validation\Constraint\ValidAt;
+use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
+use League\OAuth2\Server\CryptKey;
+use League\OAuth2\Server\CryptTrait;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class BearerTokenValidator implements AuthorizationValidatorInterface
+{
+ use CryptTrait;
+
+ /**
+ * @var AccessTokenRepositoryInterface
+ */
+ private $accessTokenRepository;
+
+ /**
+ * @var CryptKey
+ */
+ protected $publicKey;
+
+ /**
+ * @var Configuration
+ */
+ private $jwtConfiguration;
+
+ /**
+ * @var \DateInterval|null
+ */
+ private $jwtValidAtDateLeeway;
+
+ /**
+ * @param AccessTokenRepositoryInterface $accessTokenRepository
+ * @param \DateInterval|null $jwtValidAtDateLeeway
+ */
+ public function __construct(AccessTokenRepositoryInterface $accessTokenRepository, ?\DateInterval $jwtValidAtDateLeeway = null)
+ {
+ $this->accessTokenRepository = $accessTokenRepository;
+ $this->jwtValidAtDateLeeway = $jwtValidAtDateLeeway;
+ }
+
+ /**
+ * Set the public key
+ *
+ * @param CryptKey $key
+ */
+ public function setPublicKey(CryptKey $key)
+ {
+ $this->publicKey = $key;
+
+ $this->initJwtConfiguration();
+ }
+
+ /**
+ * Initialise the JWT configuration.
+ */
+ private function initJwtConfiguration()
+ {
+ $this->jwtConfiguration = Configuration::forSymmetricSigner(
+ new Sha256(),
+ InMemory::plainText('empty', 'empty')
+ );
+
+ $clock = new SystemClock(new DateTimeZone(\date_default_timezone_get()));
+ $this->jwtConfiguration->setValidationConstraints(
+ \class_exists(LooseValidAt::class)
+ ? new LooseValidAt($clock, $this->jwtValidAtDateLeeway)
+ : new ValidAt($clock, $this->jwtValidAtDateLeeway),
+ new SignedWith(
+ new Sha256(),
+ InMemory::plainText($this->publicKey->getKeyContents(), $this->publicKey->getPassPhrase() ?? '')
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateAuthorization(ServerRequestInterface $request)
+ {
+ if ($request->hasHeader('authorization') === false) {
+ throw OAuthServerException::accessDenied('Missing "Authorization" header');
+ }
+
+ $header = $request->getHeader('authorization');
+ $jwt = \trim((string) \preg_replace('/^\s*Bearer\s/', '', $header[0]));
+
+ try {
+ // Attempt to parse the JWT
+ $token = $this->jwtConfiguration->parser()->parse($jwt);
+ } catch (\Lcobucci\JWT\Exception $exception) {
+ throw OAuthServerException::accessDenied($exception->getMessage(), null, $exception);
+ }
+
+ try {
+ // Attempt to validate the JWT
+ $constraints = $this->jwtConfiguration->validationConstraints();
+ $this->jwtConfiguration->validator()->assert($token, ...$constraints);
+ } catch (RequiredConstraintsViolated $exception) {
+ throw OAuthServerException::accessDenied('Access token could not be verified');
+ }
+
+ $claims = $token->claims();
+
+ // Check if token has been revoked
+ if ($this->accessTokenRepository->isAccessTokenRevoked($claims->get('jti'))) {
+ throw OAuthServerException::accessDenied('Access token has been revoked');
+ }
+
+ // Return the request with additional attributes
+ return $request
+ ->withAttribute('oauth_access_token_id', $claims->get('jti'))
+ ->withAttribute('oauth_client_id', $this->convertSingleRecordAudToString($claims->get('aud')))
+ ->withAttribute('oauth_user_id', $claims->get('sub'))
+ ->withAttribute('oauth_scopes', $claims->get('scopes'));
+ }
+
+ /**
+ * Convert single record arrays into strings to ensure backwards compatibility between v4 and v3.x of lcobucci/jwt
+ *
+ * @param mixed $aud
+ *
+ * @return array|string
+ */
+ private function convertSingleRecordAudToString($aud)
+ {
+ return \is_array($aud) && \count($aud) === 1 ? $aud[0] : $aud;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/CodeChallengeVerifierInterface.php b/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/CodeChallengeVerifierInterface.php
new file mode 100644
index 0000000..3d7ad59
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/CodeChallengeVerifierInterface.php
@@ -0,0 +1,30 @@
+
+ * @copyright Copyright (c) Lukáš Unger
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\CodeChallengeVerifiers;
+
+interface CodeChallengeVerifierInterface
+{
+ /**
+ * Return code challenge method.
+ *
+ * @return string
+ */
+ public function getMethod();
+
+ /**
+ * Verify the code challenge.
+ *
+ * @param string $codeVerifier
+ * @param string $codeChallenge
+ *
+ * @return bool
+ */
+ public function verifyCodeChallenge($codeVerifier, $codeChallenge);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/PlainVerifier.php b/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/PlainVerifier.php
new file mode 100644
index 0000000..cf6b70a
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/PlainVerifier.php
@@ -0,0 +1,36 @@
+
+ * @copyright Copyright (c) Lukáš Unger
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\CodeChallengeVerifiers;
+
+class PlainVerifier implements CodeChallengeVerifierInterface
+{
+ /**
+ * Return code challenge method.
+ *
+ * @return string
+ */
+ public function getMethod()
+ {
+ return 'plain';
+ }
+
+ /**
+ * Verify the code challenge.
+ *
+ * @param string $codeVerifier
+ * @param string $codeChallenge
+ *
+ * @return bool
+ */
+ public function verifyCodeChallenge($codeVerifier, $codeChallenge)
+ {
+ return \hash_equals($codeVerifier, $codeChallenge);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/S256Verifier.php b/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/S256Verifier.php
new file mode 100644
index 0000000..f70790a
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/CodeChallengeVerifiers/S256Verifier.php
@@ -0,0 +1,39 @@
+
+ * @copyright Copyright (c) Lukáš Unger
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\CodeChallengeVerifiers;
+
+class S256Verifier implements CodeChallengeVerifierInterface
+{
+ /**
+ * Return code challenge method.
+ *
+ * @return string
+ */
+ public function getMethod()
+ {
+ return 'S256';
+ }
+
+ /**
+ * Verify the code challenge.
+ *
+ * @param string $codeVerifier
+ * @param string $codeChallenge
+ *
+ * @return bool
+ */
+ public function verifyCodeChallenge($codeVerifier, $codeChallenge)
+ {
+ return \hash_equals(
+ \strtr(\rtrim(\base64_encode(\hash('sha256', $codeVerifier, true)), '='), '+/', '-_'),
+ $codeChallenge
+ );
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/CryptKey.php b/api_candidatos/vendor/league/oauth2-server/src/CryptKey.php
new file mode 100644
index 0000000..b9d7f77
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/CryptKey.php
@@ -0,0 +1,138 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use LogicException;
+
+class CryptKey
+{
+ /** @deprecated left for backward compatibility check */
+ const RSA_KEY_PATTERN =
+ '/^(-----BEGIN (RSA )?(PUBLIC|PRIVATE) KEY-----)\R.*(-----END (RSA )?(PUBLIC|PRIVATE) KEY-----)\R?$/s';
+
+ private const FILE_PREFIX = 'file://';
+
+ /**
+ * @var string Key contents
+ */
+ protected $keyContents;
+
+ /**
+ * @var string
+ */
+ protected $keyPath;
+
+ /**
+ * @var null|string
+ */
+ protected $passPhrase;
+
+ /**
+ * @param string $keyPath
+ * @param null|string $passPhrase
+ * @param bool $keyPermissionsCheck
+ */
+ public function __construct($keyPath, $passPhrase = null, $keyPermissionsCheck = true)
+ {
+ $this->passPhrase = $passPhrase;
+
+ if (\strpos($keyPath, self::FILE_PREFIX) !== 0 && $this->isValidKey($keyPath, $this->passPhrase ?? '')) {
+ $this->keyContents = $keyPath;
+ $this->keyPath = '';
+ // There's no file, so no need for permission check.
+ $keyPermissionsCheck = false;
+ } elseif (\is_file($keyPath)) {
+ if (\strpos($keyPath, self::FILE_PREFIX) !== 0) {
+ $keyPath = self::FILE_PREFIX . $keyPath;
+ }
+
+ if (!\is_readable($keyPath)) {
+ throw new LogicException(\sprintf('Key path "%s" does not exist or is not readable', $keyPath));
+ }
+ $this->keyContents = \file_get_contents($keyPath);
+ $this->keyPath = $keyPath;
+ if (!$this->isValidKey($this->keyContents, $this->passPhrase ?? '')) {
+ throw new LogicException('Unable to read key from file ' . $keyPath);
+ }
+ } else {
+ throw new LogicException('Invalid key supplied');
+ }
+
+ /*if ($keyPermissionsCheck === true) {
+ // Verify the permissions of the key
+ $keyPathPerms = \decoct(\fileperms($this->keyPath) & 0777);
+ if (\in_array($keyPathPerms, ['400', '440', '600', '640', '660'], true) === false) {
+ \trigger_error(
+ \sprintf(
+ 'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s',
+ $this->keyPath,
+ $keyPathPerms
+ ),
+ E_USER_NOTICE
+ );
+ }
+ }*/
+ }
+
+ /**
+ * Get key contents
+ *
+ * @return string Key contents
+ */
+ public function getKeyContents(): string
+ {
+ return $this->keyContents;
+ }
+
+ /**
+ * Validate key contents.
+ *
+ * @param string $contents
+ * @param string $passPhrase
+ *
+ * @return bool
+ */
+ private function isValidKey($contents, $passPhrase)
+ {
+ $pkey = \openssl_pkey_get_private($contents, $passPhrase) ?: \openssl_pkey_get_public($contents);
+ if ($pkey === false) {
+ return false;
+ }
+ $details = \openssl_pkey_get_details($pkey);
+
+ return $details !== false && \in_array(
+ $details['type'] ?? -1,
+ [OPENSSL_KEYTYPE_RSA, OPENSSL_KEYTYPE_EC],
+ true
+ );
+ }
+
+ /**
+ * Retrieve key path.
+ *
+ * @return string
+ */
+ public function getKeyPath()
+ {
+ return $this->keyPath;
+ }
+
+ /**
+ * Retrieve key pass phrase.
+ *
+ * @return null|string
+ */
+ public function getPassPhrase()
+ {
+ return $this->passPhrase;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/CryptTrait.php b/api_candidatos/vendor/league/oauth2-server/src/CryptTrait.php
new file mode 100644
index 0000000..a17e697
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/CryptTrait.php
@@ -0,0 +1,87 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use Defuse\Crypto\Crypto;
+use Defuse\Crypto\Key;
+use Exception;
+use LogicException;
+
+trait CryptTrait
+{
+ /**
+ * @var string|Key|null
+ */
+ protected $encryptionKey;
+
+ /**
+ * Encrypt data with encryptionKey.
+ *
+ * @param string $unencryptedData
+ *
+ * @throws LogicException
+ *
+ * @return string
+ */
+ protected function encrypt($unencryptedData)
+ {
+ try {
+ if ($this->encryptionKey instanceof Key) {
+ return Crypto::encrypt($unencryptedData, $this->encryptionKey);
+ }
+
+ if (\is_string($this->encryptionKey)) {
+ return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey);
+ }
+
+ throw new LogicException('Encryption key not set when attempting to encrypt');
+ } catch (Exception $e) {
+ throw new LogicException($e->getMessage(), 0, $e);
+ }
+ }
+
+ /**
+ * Decrypt data with encryptionKey.
+ *
+ * @param string $encryptedData
+ *
+ * @throws LogicException
+ *
+ * @return string
+ */
+ protected function decrypt($encryptedData)
+ {
+ try {
+ if ($this->encryptionKey instanceof Key) {
+ return Crypto::decrypt($encryptedData, $this->encryptionKey);
+ }
+
+ if (\is_string($this->encryptionKey)) {
+ return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey);
+ }
+
+ throw new LogicException('Encryption key not set when attempting to decrypt');
+ } catch (Exception $e) {
+ throw new LogicException($e->getMessage(), 0, $e);
+ }
+ }
+
+ /**
+ * Set the encryption key
+ *
+ * @param string|Key $key
+ */
+ public function setEncryptionKey($key = null)
+ {
+ $this->encryptionKey = $key;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/AccessTokenEntityInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/AccessTokenEntityInterface.php
new file mode 100644
index 0000000..fd45991
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/AccessTokenEntityInterface.php
@@ -0,0 +1,25 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+use League\OAuth2\Server\CryptKey;
+
+interface AccessTokenEntityInterface extends TokenInterface
+{
+ /**
+ * Set a private key used to encrypt the access token.
+ */
+ public function setPrivateKey(CryptKey $privateKey);
+
+ /**
+ * Generate a string representation of the access token.
+ */
+ public function __toString();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/AuthCodeEntityInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/AuthCodeEntityInterface.php
new file mode 100644
index 0000000..00e939c
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/AuthCodeEntityInterface.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+interface AuthCodeEntityInterface extends TokenInterface
+{
+ /**
+ * @return string|null
+ */
+ public function getRedirectUri();
+
+ /**
+ * @param string $uri
+ */
+ public function setRedirectUri($uri);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/ClientEntityInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/ClientEntityInterface.php
new file mode 100644
index 0000000..971c612
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/ClientEntityInterface.php
@@ -0,0 +1,43 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+interface ClientEntityInterface
+{
+ /**
+ * Get the client's identifier.
+ *
+ * @return string
+ */
+ public function getIdentifier();
+
+ /**
+ * Get the client's name.
+ *
+ * @return string
+ */
+ public function getName();
+
+ /**
+ * Returns the registered redirect URI (as a string).
+ *
+ * Alternatively return an indexed array of redirect URIs.
+ *
+ * @return string|string[]
+ */
+ public function getRedirectUri();
+
+ /**
+ * Returns true if the client is confidential.
+ *
+ * @return bool
+ */
+ public function isConfidential();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/RefreshTokenEntityInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/RefreshTokenEntityInterface.php
new file mode 100644
index 0000000..551ad05
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/RefreshTokenEntityInterface.php
@@ -0,0 +1,57 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+use DateTimeImmutable;
+
+interface RefreshTokenEntityInterface
+{
+ /**
+ * Get the token's identifier.
+ *
+ * @return string
+ */
+ public function getIdentifier();
+
+ /**
+ * Set the token's identifier.
+ *
+ * @param mixed $identifier
+ */
+ public function setIdentifier($identifier);
+
+ /**
+ * Get the token's expiry date time.
+ *
+ * @return DateTimeImmutable
+ */
+ public function getExpiryDateTime();
+
+ /**
+ * Set the date time when the token expires.
+ *
+ * @param DateTimeImmutable $dateTime
+ */
+ public function setExpiryDateTime(DateTimeImmutable $dateTime);
+
+ /**
+ * Set the access token that the refresh token was associated with.
+ *
+ * @param AccessTokenEntityInterface $accessToken
+ */
+ public function setAccessToken(AccessTokenEntityInterface $accessToken);
+
+ /**
+ * Get the access token that the refresh token was originally associated with.
+ *
+ * @return AccessTokenEntityInterface
+ */
+ public function getAccessToken();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/ScopeEntityInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/ScopeEntityInterface.php
new file mode 100644
index 0000000..26748e0
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/ScopeEntityInterface.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+use JsonSerializable;
+
+interface ScopeEntityInterface extends JsonSerializable
+{
+ /**
+ * Get the scope's identifier.
+ *
+ * @return string
+ */
+ public function getIdentifier();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/TokenInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/TokenInterface.php
new file mode 100644
index 0000000..7b063e1
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/TokenInterface.php
@@ -0,0 +1,85 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+use DateTimeImmutable;
+
+interface TokenInterface
+{
+ /**
+ * Get the token's identifier.
+ *
+ * @return string
+ */
+ public function getIdentifier();
+
+ /**
+ * Set the token's identifier.
+ *
+ * @param mixed $identifier
+ */
+ public function setIdentifier($identifier);
+
+ /**
+ * Get the token's expiry date time.
+ *
+ * @return DateTimeImmutable
+ */
+ public function getExpiryDateTime();
+
+ /**
+ * Set the date time when the token expires.
+ *
+ * @param DateTimeImmutable $dateTime
+ */
+ public function setExpiryDateTime(DateTimeImmutable $dateTime);
+
+ /**
+ * Set the identifier of the user associated with the token.
+ *
+ * @param string|int|null $identifier The identifier of the user
+ */
+ public function setUserIdentifier($identifier);
+
+ /**
+ * Get the token user's identifier.
+ *
+ * @return string|int|null
+ */
+ public function getUserIdentifier();
+
+ /**
+ * Get the client that the token was issued to.
+ *
+ * @return ClientEntityInterface
+ */
+ public function getClient();
+
+ /**
+ * Set the client that the token was issued to.
+ *
+ * @param ClientEntityInterface $client
+ */
+ public function setClient(ClientEntityInterface $client);
+
+ /**
+ * Associate a scope with the token.
+ *
+ * @param ScopeEntityInterface $scope
+ */
+ public function addScope(ScopeEntityInterface $scope);
+
+ /**
+ * Return an array of scopes associated with the token.
+ *
+ * @return ScopeEntityInterface[]
+ */
+ public function getScopes();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/AccessTokenTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/AccessTokenTrait.php
new file mode 100644
index 0000000..81b6343
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/AccessTokenTrait.php
@@ -0,0 +1,105 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+use DateTimeImmutable;
+use Lcobucci\JWT\Configuration;
+use Lcobucci\JWT\Signer\Key\InMemory;
+use Lcobucci\JWT\Signer\Rsa\Sha256;
+use Lcobucci\JWT\Token;
+use League\OAuth2\Server\CryptKey;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+
+trait AccessTokenTrait
+{
+ /**
+ * @var CryptKey
+ */
+ private $privateKey;
+
+ /**
+ * @var Configuration
+ */
+ private $jwtConfiguration;
+
+ /**
+ * Set the private key used to encrypt this access token.
+ */
+ public function setPrivateKey(CryptKey $privateKey)
+ {
+ $this->privateKey = $privateKey;
+ }
+
+ /**
+ * Initialise the JWT Configuration.
+ */
+ public function initJwtConfiguration()
+ {
+ $this->jwtConfiguration = Configuration::forAsymmetricSigner(
+ new Sha256(),
+ InMemory::plainText($this->privateKey->getKeyContents(), $this->privateKey->getPassPhrase() ?? ''),
+ InMemory::plainText('empty', 'empty')
+ );
+ }
+
+ /**
+ * Generate a JWT from the access token
+ *
+ * @return Token
+ */
+ private function convertToJWT()
+ {
+ $this->initJwtConfiguration();
+
+ return $this->jwtConfiguration->builder()
+ ->permittedFor($this->getClient()->getIdentifier())
+ ->identifiedBy($this->getIdentifier())
+ ->issuedAt(new DateTimeImmutable())
+ ->canOnlyBeUsedAfter(new DateTimeImmutable())
+ ->expiresAt($this->getExpiryDateTime())
+ ->relatedTo((string) $this->getUserIdentifier())
+ ->withClaim('scopes', $this->getScopes())
+ ->getToken($this->jwtConfiguration->signer(), $this->jwtConfiguration->signingKey());
+ }
+
+ /**
+ * Generate a string representation from the access token
+ */
+ public function __toString()
+ {
+ return $this->convertToJWT()->toString();
+ }
+
+ /**
+ * @return ClientEntityInterface
+ */
+ abstract public function getClient();
+
+ /**
+ * @return DateTimeImmutable
+ */
+ abstract public function getExpiryDateTime();
+
+ /**
+ * @return string|int
+ */
+ abstract public function getUserIdentifier();
+
+ /**
+ * @return ScopeEntityInterface[]
+ */
+ abstract public function getScopes();
+
+ /**
+ * @return string
+ */
+ abstract public function getIdentifier();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/AuthCodeTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/AuthCodeTrait.php
new file mode 100644
index 0000000..542d367
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/AuthCodeTrait.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+trait AuthCodeTrait
+{
+ /**
+ * @var null|string
+ */
+ protected $redirectUri;
+
+ /**
+ * @return string|null
+ */
+ public function getRedirectUri()
+ {
+ return $this->redirectUri;
+ }
+
+ /**
+ * @param string $uri
+ */
+ public function setRedirectUri($uri)
+ {
+ $this->redirectUri = $uri;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/ClientTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/ClientTrait.php
new file mode 100644
index 0000000..370163c
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/ClientTrait.php
@@ -0,0 +1,62 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+trait ClientTrait
+{
+ /**
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * @var string|string[]
+ */
+ protected $redirectUri;
+
+ /**
+ * @var bool
+ */
+ protected $isConfidential = false;
+
+ /**
+ * Get the client's name.
+ *
+ * @return string
+ *
+ * @codeCoverageIgnore
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Returns the registered redirect URI (as a string).
+ *
+ * Alternatively return an indexed array of redirect URIs.
+ *
+ * @return string|string[]
+ */
+ public function getRedirectUri()
+ {
+ return $this->redirectUri;
+ }
+
+ /**
+ * Returns true if the client is confidential.
+ *
+ * @return bool
+ */
+ public function isConfidential()
+ {
+ return $this->isConfidential;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/EntityTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/EntityTrait.php
new file mode 100644
index 0000000..0545292
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/EntityTrait.php
@@ -0,0 +1,34 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+trait EntityTrait
+{
+ /**
+ * @var string
+ */
+ protected $identifier;
+
+ /**
+ * @return mixed
+ */
+ public function getIdentifier()
+ {
+ return $this->identifier;
+ }
+
+ /**
+ * @param mixed $identifier
+ */
+ public function setIdentifier($identifier)
+ {
+ $this->identifier = $identifier;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/RefreshTokenTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/RefreshTokenTrait.php
new file mode 100644
index 0000000..f0f1544
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/RefreshTokenTrait.php
@@ -0,0 +1,62 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+use DateTimeImmutable;
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+
+trait RefreshTokenTrait
+{
+ /**
+ * @var AccessTokenEntityInterface
+ */
+ protected $accessToken;
+
+ /**
+ * @var DateTimeImmutable
+ */
+ protected $expiryDateTime;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAccessToken(AccessTokenEntityInterface $accessToken)
+ {
+ $this->accessToken = $accessToken;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessToken()
+ {
+ return $this->accessToken;
+ }
+
+ /**
+ * Get the token's expiry date time.
+ *
+ * @return DateTimeImmutable
+ */
+ public function getExpiryDateTime()
+ {
+ return $this->expiryDateTime;
+ }
+
+ /**
+ * Set the date time when the token expires.
+ *
+ * @param DateTimeImmutable $dateTime
+ */
+ public function setExpiryDateTime(DateTimeImmutable $dateTime)
+ {
+ $this->expiryDateTime = $dateTime;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/ScopeTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/ScopeTrait.php
new file mode 100644
index 0000000..7eacc33
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/ScopeTrait.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) Andrew Millington
+ * @license http://mit-license.org
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+trait ScopeTrait
+{
+ /**
+ * Serialize the object to the scopes string identifier when using json_encode().
+ *
+ * @return string
+ */
+ #[\ReturnTypeWillChange]
+ public function jsonSerialize()
+ {
+ return $this->getIdentifier();
+ }
+
+ /**
+ * @return string
+ */
+ abstract public function getIdentifier();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/TokenEntityTrait.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/TokenEntityTrait.php
new file mode 100644
index 0000000..83b1723
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/Traits/TokenEntityTrait.php
@@ -0,0 +1,117 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities\Traits;
+
+use DateTimeImmutable;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+
+trait TokenEntityTrait
+{
+ /**
+ * @var ScopeEntityInterface[]
+ */
+ protected $scopes = [];
+
+ /**
+ * @var DateTimeImmutable
+ */
+ protected $expiryDateTime;
+
+ /**
+ * @var string|int|null
+ */
+ protected $userIdentifier;
+
+ /**
+ * @var ClientEntityInterface
+ */
+ protected $client;
+
+ /**
+ * Associate a scope with the token.
+ *
+ * @param ScopeEntityInterface $scope
+ */
+ public function addScope(ScopeEntityInterface $scope)
+ {
+ $this->scopes[$scope->getIdentifier()] = $scope;
+ }
+
+ /**
+ * Return an array of scopes associated with the token.
+ *
+ * @return ScopeEntityInterface[]
+ */
+ public function getScopes()
+ {
+ return \array_values($this->scopes);
+ }
+
+ /**
+ * Get the token's expiry date time.
+ *
+ * @return DateTimeImmutable
+ */
+ public function getExpiryDateTime()
+ {
+ return $this->expiryDateTime;
+ }
+
+ /**
+ * Set the date time when the token expires.
+ *
+ * @param DateTimeImmutable $dateTime
+ */
+ public function setExpiryDateTime(DateTimeImmutable $dateTime)
+ {
+ $this->expiryDateTime = $dateTime;
+ }
+
+ /**
+ * Set the identifier of the user associated with the token.
+ *
+ * @param string|int|null $identifier The identifier of the user
+ */
+ public function setUserIdentifier($identifier)
+ {
+ $this->userIdentifier = $identifier;
+ }
+
+ /**
+ * Get the token user's identifier.
+ *
+ * @return string|int|null
+ */
+ public function getUserIdentifier()
+ {
+ return $this->userIdentifier;
+ }
+
+ /**
+ * Get the client that the token was issued to.
+ *
+ * @return ClientEntityInterface
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ /**
+ * Set the client that the token was issued to.
+ *
+ * @param ClientEntityInterface $client
+ */
+ public function setClient(ClientEntityInterface $client)
+ {
+ $this->client = $client;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Entities/UserEntityInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Entities/UserEntityInterface.php
new file mode 100644
index 0000000..c71cb9c
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Entities/UserEntityInterface.php
@@ -0,0 +1,20 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Entities;
+
+interface UserEntityInterface
+{
+ /**
+ * Return the user's identifier.
+ *
+ * @return mixed
+ */
+ public function getIdentifier();
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Exception/OAuthServerException.php b/api_candidatos/vendor/league/oauth2-server/src/Exception/OAuthServerException.php
new file mode 100644
index 0000000..a4dcd17
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Exception/OAuthServerException.php
@@ -0,0 +1,416 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Exception;
+
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Throwable;
+
+class OAuthServerException extends Exception
+{
+ /**
+ * @var int
+ */
+ private $httpStatusCode;
+
+ /**
+ * @var string
+ */
+ private $errorType;
+
+ /**
+ * @var null|string
+ */
+ private $hint;
+
+ /**
+ * @var null|string
+ */
+ private $redirectUri;
+
+ /**
+ * @var array
+ */
+ private $payload;
+
+ /**
+ * @var ServerRequestInterface
+ */
+ private $serverRequest;
+
+ /**
+ * Throw a new exception.
+ *
+ * @param string $message Error message
+ * @param int $code Error code
+ * @param string $errorType Error type
+ * @param int $httpStatusCode HTTP status code to send (default = 400)
+ * @param null|string $hint A helper hint
+ * @param null|string $redirectUri A HTTP URI to redirect the user back to
+ * @param Throwable $previous Previous exception
+ */
+ public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null, ?Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ $this->httpStatusCode = $httpStatusCode;
+ $this->errorType = $errorType;
+ $this->hint = $hint;
+ $this->redirectUri = $redirectUri;
+ $this->payload = [
+ 'error' => $errorType,
+ 'error_description' => $message,
+ ];
+ if ($hint !== null) {
+ $this->payload['hint'] = $hint;
+ }
+ }
+
+ /**
+ * Returns the current payload.
+ *
+ * @return array
+ */
+ public function getPayload()
+ {
+ $payload = $this->payload;
+
+ // The "message" property is deprecated and replaced by "error_description"
+ // TODO: remove "message" property
+ if (isset($payload['error_description']) && !isset($payload['message'])) {
+ $payload['message'] = $payload['error_description'];
+ }
+
+ return $payload;
+ }
+
+ /**
+ * Updates the current payload.
+ *
+ * @param array $payload
+ */
+ public function setPayload(array $payload)
+ {
+ $this->payload = $payload;
+ }
+
+ /**
+ * Set the server request that is responsible for generating the exception
+ *
+ * @param ServerRequestInterface $serverRequest
+ */
+ public function setServerRequest(ServerRequestInterface $serverRequest)
+ {
+ $this->serverRequest = $serverRequest;
+ }
+
+ /**
+ * Unsupported grant type error.
+ *
+ * @return static
+ */
+ public static function unsupportedGrantType()
+ {
+ $errorMessage = 'The authorization grant type is not supported by the authorization server.';
+ $hint = 'Check that all required parameters have been provided';
+
+ return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
+ }
+
+ /**
+ * Invalid request error.
+ *
+ * @param string $parameter The invalid parameter
+ * @param null|string $hint
+ * @param Throwable $previous Previous exception
+ *
+ * @return static
+ */
+ public static function invalidRequest($parameter, $hint = null, ?Throwable $previous = null)
+ {
+ $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
+ 'includes a parameter more than once, or is otherwise malformed.';
+ $hint = ($hint === null) ? \sprintf('Check the `%s` parameter', $parameter) : $hint;
+
+ return new static($errorMessage, 3, 'invalid_request', 400, $hint, null, $previous);
+ }
+
+ /**
+ * Invalid client error.
+ *
+ * @param ServerRequestInterface $serverRequest
+ *
+ * @return static
+ */
+ public static function invalidClient(ServerRequestInterface $serverRequest)
+ {
+ $exception = new static('Client authentication failed', 4, 'invalid_client', 401);
+
+ $exception->setServerRequest($serverRequest);
+
+ return $exception;
+ }
+
+ /**
+ * Invalid scope error.
+ *
+ * @param string $scope The bad scope
+ * @param null|string $redirectUri A HTTP URI to redirect the user back to
+ *
+ * @return static
+ */
+ public static function invalidScope($scope, $redirectUri = null)
+ {
+ $errorMessage = 'The requested scope is invalid, unknown, or malformed';
+
+ if (empty($scope)) {
+ $hint = 'Specify a scope in the request or set a default scope';
+ } else {
+ $hint = \sprintf(
+ 'Check the `%s` scope',
+ \htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
+ );
+ }
+
+ return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
+ }
+
+ /**
+ * Invalid credentials error.
+ *
+ * @return static
+ */
+ public static function invalidCredentials()
+ {
+ return new static('The user credentials were incorrect.', 6, 'invalid_grant', 400);
+ }
+
+ /**
+ * Server error.
+ *
+ * @param string $hint
+ * @param Throwable $previous
+ *
+ * @return static
+ *
+ * @codeCoverageIgnore
+ */
+ public static function serverError($hint, ?Throwable $previous = null)
+ {
+ return new static(
+ 'The authorization server encountered an unexpected condition which prevented it from fulfilling'
+ . ' the request: ' . $hint,
+ 7,
+ 'server_error',
+ 500,
+ null,
+ null,
+ $previous
+ );
+ }
+
+ /**
+ * Invalid refresh token.
+ *
+ * @param null|string $hint
+ * @param Throwable $previous
+ *
+ * @return static
+ */
+ public static function invalidRefreshToken($hint = null, ?Throwable $previous = null)
+ {
+ return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint, null, $previous);
+ }
+
+ /**
+ * Access denied.
+ *
+ * @param null|string $hint
+ * @param null|string $redirectUri
+ * @param Throwable $previous
+ *
+ * @return static
+ */
+ public static function accessDenied($hint = null, $redirectUri = null, ?Throwable $previous = null)
+ {
+ return new static(
+ 'The resource owner or authorization server denied the request.',
+ 9,
+ 'access_denied',
+ 401,
+ $hint,
+ $redirectUri,
+ $previous
+ );
+ }
+
+ /**
+ * Invalid grant.
+ *
+ * @param string $hint
+ *
+ * @return static
+ */
+ public static function invalidGrant($hint = '')
+ {
+ return new static(
+ 'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
+ . 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
+ . 'or was issued to another client.',
+ 10,
+ 'invalid_grant',
+ 400,
+ $hint
+ );
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorType()
+ {
+ return $this->errorType;
+ }
+
+ /**
+ * Generate a HTTP response.
+ *
+ * @param ResponseInterface $response
+ * @param bool $useFragment True if errors should be in the URI fragment instead of query string
+ * @param int $jsonOptions options passed to json_encode
+ *
+ * @return ResponseInterface
+ */
+ public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
+ {
+ $headers = $this->getHttpHeaders();
+
+ $payload = $this->getPayload();
+
+ if ($this->redirectUri !== null) {
+ if ($useFragment === true) {
+ $this->redirectUri .= (\strstr($this->redirectUri, '#') === false) ? '#' : '&';
+ } else {
+ $this->redirectUri .= (\strstr($this->redirectUri, '?') === false) ? '?' : '&';
+ }
+
+ return $response->withStatus(302)->withHeader('Location', $this->redirectUri . \http_build_query($payload));
+ }
+
+ foreach ($headers as $header => $content) {
+ $response = $response->withHeader($header, $content);
+ }
+
+ $responseBody = \json_encode($payload, $jsonOptions) ?: 'JSON encoding of payload failed';
+
+ $response->getBody()->write($responseBody);
+
+ return $response->withStatus($this->getHttpStatusCode());
+ }
+
+ /**
+ * Get all headers that have to be send with the error response.
+ *
+ * @return array Array with header values
+ */
+ public function getHttpHeaders()
+ {
+ $headers = [
+ 'Content-type' => 'application/json',
+ ];
+
+ // Add "WWW-Authenticate" header
+ //
+ // RFC 6749, section 5.2.:
+ // "If the client attempted to authenticate via the 'Authorization'
+ // request header field, the authorization server MUST
+ // respond with an HTTP 401 (Unauthorized) status code and
+ // include the "WWW-Authenticate" response header field
+ // matching the authentication scheme used by the client.
+ if ($this->errorType === 'invalid_client' && $this->requestHasAuthorizationHeader()) {
+ $authScheme = \strpos($this->serverRequest->getHeader('Authorization')[0], 'Bearer') === 0 ? 'Bearer' : 'Basic';
+
+ $headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Check if the exception has an associated redirect URI.
+ *
+ * Returns whether the exception includes a redirect, since
+ * getHttpStatusCode() doesn't return a 302 when there's a
+ * redirect enabled. This helps when you want to override local
+ * error pages but want to let redirects through.
+ *
+ * @return bool
+ */
+ public function hasRedirect()
+ {
+ return $this->redirectUri !== null;
+ }
+
+ /**
+ * Returns the Redirect URI used for redirecting.
+ *
+ * @return string|null
+ */
+ public function getRedirectUri()
+ {
+ return $this->redirectUri;
+ }
+
+ /**
+ * Returns the HTTP status code to send when the exceptions is output.
+ *
+ * @return int
+ */
+ public function getHttpStatusCode()
+ {
+ return $this->httpStatusCode;
+ }
+
+ /**
+ * @return null|string
+ */
+ public function getHint()
+ {
+ return $this->hint;
+ }
+
+ /**
+ * Check if the request has a non-empty 'Authorization' header value.
+ *
+ * Returns true if the header is present and not an empty string, false
+ * otherwise.
+ *
+ * @return bool
+ */
+ private function requestHasAuthorizationHeader()
+ {
+ if (!$this->serverRequest->hasHeader('Authorization')) {
+ return false;
+ }
+
+ $authorizationHeader = $this->serverRequest->getHeader('Authorization');
+
+ // Common .htaccess configurations yield an empty string for the
+ // 'Authorization' header when one is not provided by the client.
+ // For practical purposes that case should be treated as though the
+ // header isn't present.
+ // See https://github.com/thephpleague/oauth2-server/issues/1162
+ if (empty($authorizationHeader) || empty($authorizationHeader[0])) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Exception/UniqueTokenIdentifierConstraintViolationException.php b/api_candidatos/vendor/league/oauth2-server/src/Exception/UniqueTokenIdentifierConstraintViolationException.php
new file mode 100644
index 0000000..175ab3a
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Exception/UniqueTokenIdentifierConstraintViolationException.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Exception;
+
+class UniqueTokenIdentifierConstraintViolationException extends OAuthServerException
+{
+ /**
+ * @return UniqueTokenIdentifierConstraintViolationException
+ */
+ public static function create()
+ {
+ $errorMessage = 'Could not create unique access token identifier';
+
+ return new static($errorMessage, 100, 'access_token_duplicate', 500);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/AbstractAuthorizeGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/AbstractAuthorizeGrant.php
new file mode 100644
index 0000000..716c9bb
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/AbstractAuthorizeGrant.php
@@ -0,0 +1,29 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+abstract class AbstractAuthorizeGrant extends AbstractGrant
+{
+ /**
+ * @param string $uri
+ * @param array $params
+ * @param string $queryDelimiter
+ *
+ * @return string
+ */
+ public function makeRedirectUri($uri, $params = [], $queryDelimiter = '?')
+ {
+ $uri .= (\strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&';
+
+ return $uri . \http_build_query($params);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/AbstractGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/AbstractGrant.php
new file mode 100644
index 0000000..c8eb6b8
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/AbstractGrant.php
@@ -0,0 +1,621 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use DateTimeImmutable;
+use Error;
+use Exception;
+use League\Event\EmitterAwareTrait;
+use League\OAuth2\Server\CryptKey;
+use League\OAuth2\Server\CryptTrait;
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
+use League\OAuth2\Server\RedirectUriValidators\RedirectUriValidator;
+use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
+use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
+use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
+use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
+use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
+use League\OAuth2\Server\Repositories\UserRepositoryInterface;
+use League\OAuth2\Server\RequestEvent;
+use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
+use LogicException;
+use Psr\Http\Message\ServerRequestInterface;
+use TypeError;
+
+/**
+ * Abstract grant class.
+ */
+abstract class AbstractGrant implements GrantTypeInterface
+{
+ use EmitterAwareTrait, CryptTrait;
+
+ const SCOPE_DELIMITER_STRING = ' ';
+
+ const MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS = 10;
+
+ /**
+ * @var ClientRepositoryInterface
+ */
+ protected $clientRepository;
+
+ /**
+ * @var AccessTokenRepositoryInterface
+ */
+ protected $accessTokenRepository;
+
+ /**
+ * @var ScopeRepositoryInterface
+ */
+ protected $scopeRepository;
+
+ /**
+ * @var AuthCodeRepositoryInterface
+ */
+ protected $authCodeRepository;
+
+ /**
+ * @var RefreshTokenRepositoryInterface
+ */
+ protected $refreshTokenRepository;
+
+ /**
+ * @var UserRepositoryInterface
+ */
+ protected $userRepository;
+
+ /**
+ * @var DateInterval
+ */
+ protected $refreshTokenTTL;
+
+ /**
+ * @var CryptKey
+ */
+ protected $privateKey;
+
+ /**
+ * @var string
+ */
+ protected $defaultScope;
+
+ /**
+ * @var bool
+ */
+ protected $revokeRefreshTokens;
+
+ /**
+ * @param ClientRepositoryInterface $clientRepository
+ */
+ public function setClientRepository(ClientRepositoryInterface $clientRepository)
+ {
+ $this->clientRepository = $clientRepository;
+ }
+
+ /**
+ * @param AccessTokenRepositoryInterface $accessTokenRepository
+ */
+ public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository)
+ {
+ $this->accessTokenRepository = $accessTokenRepository;
+ }
+
+ /**
+ * @param ScopeRepositoryInterface $scopeRepository
+ */
+ public function setScopeRepository(ScopeRepositoryInterface $scopeRepository)
+ {
+ $this->scopeRepository = $scopeRepository;
+ }
+
+ /**
+ * @param RefreshTokenRepositoryInterface $refreshTokenRepository
+ */
+ public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
+ {
+ $this->refreshTokenRepository = $refreshTokenRepository;
+ }
+
+ /**
+ * @param AuthCodeRepositoryInterface $authCodeRepository
+ */
+ public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository)
+ {
+ $this->authCodeRepository = $authCodeRepository;
+ }
+
+ /**
+ * @param UserRepositoryInterface $userRepository
+ */
+ public function setUserRepository(UserRepositoryInterface $userRepository)
+ {
+ $this->userRepository = $userRepository;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRefreshTokenTTL(DateInterval $refreshTokenTTL)
+ {
+ $this->refreshTokenTTL = $refreshTokenTTL;
+ }
+
+ /**
+ * Set the private key
+ *
+ * @param CryptKey $key
+ */
+ public function setPrivateKey(CryptKey $key)
+ {
+ $this->privateKey = $key;
+ }
+
+ /**
+ * @param string $scope
+ */
+ public function setDefaultScope($scope)
+ {
+ $this->defaultScope = $scope;
+ }
+
+ /**
+ * @param bool $revokeRefreshTokens
+ */
+ public function revokeRefreshTokens(bool $revokeRefreshTokens)
+ {
+ $this->revokeRefreshTokens = $revokeRefreshTokens;
+ }
+
+ /**
+ * Validate the client.
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @throws OAuthServerException
+ *
+ * @return ClientEntityInterface
+ */
+ protected function validateClient(ServerRequestInterface $request)
+ {
+ [$clientId, $clientSecret] = $this->getClientCredentials($request);
+
+ if ($this->clientRepository->validateClient($clientId, $clientSecret, $this->getIdentifier()) === false) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
+
+ throw OAuthServerException::invalidClient($request);
+ }
+
+ $client = $this->getClientEntityOrFail($clientId, $request);
+
+ // If a redirect URI is provided ensure it matches what is pre-registered
+ $redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
+
+ if ($redirectUri !== null) {
+ if (!\is_string($redirectUri)) {
+ throw OAuthServerException::invalidRequest('redirect_uri');
+ }
+
+ $this->validateRedirectUri($redirectUri, $client, $request);
+ }
+
+ return $client;
+ }
+
+ /**
+ * Wrapper around ClientRepository::getClientEntity() that ensures we emit
+ * an event and throw an exception if the repo doesn't return a client
+ * entity.
+ *
+ * This is a bit of defensive coding because the interface contract
+ * doesn't actually enforce non-null returns/exception-on-no-client so
+ * getClientEntity might return null. By contrast, this method will
+ * always either return a ClientEntityInterface or throw.
+ *
+ * @param string $clientId
+ * @param ServerRequestInterface $request
+ *
+ * @return ClientEntityInterface
+ */
+ protected function getClientEntityOrFail($clientId, ServerRequestInterface $request)
+ {
+ $client = $this->clientRepository->getClientEntity($clientId);
+
+ if ($client instanceof ClientEntityInterface === false) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
+ throw OAuthServerException::invalidClient($request);
+ }
+
+ return $client;
+ }
+
+ /**
+ * Gets the client credentials from the request from the request body or
+ * the Http Basic Authorization header
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @return array
+ */
+ protected function getClientCredentials(ServerRequestInterface $request)
+ {
+ [$basicAuthUser, $basicAuthPassword] = $this->getBasicAuthCredentials($request);
+
+ $clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
+
+ if (\is_null($clientId)) {
+ throw OAuthServerException::invalidRequest('client_id');
+ }
+
+ $clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
+
+ if ($clientSecret !== null && !\is_string($clientSecret)) {
+ throw OAuthServerException::invalidRequest('client_secret');
+ }
+
+ return [$clientId, $clientSecret];
+ }
+
+ /**
+ * Validate redirectUri from the request.
+ * If a redirect URI is provided ensure it matches what is pre-registered
+ *
+ * @param string $redirectUri
+ * @param ClientEntityInterface $client
+ * @param ServerRequestInterface $request
+ *
+ * @throws OAuthServerException
+ */
+ protected function validateRedirectUri(
+ string $redirectUri,
+ ClientEntityInterface $client,
+ ServerRequestInterface $request
+ ) {
+ $validator = new RedirectUriValidator($client->getRedirectUri());
+ if (!$validator->validateRedirectUri($redirectUri)) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
+ throw OAuthServerException::invalidClient($request);
+ }
+ }
+
+ /**
+ * Validate scopes in the request.
+ *
+ * @param string|array|null $scopes
+ * @param string $redirectUri
+ *
+ * @throws OAuthServerException
+ *
+ * @return ScopeEntityInterface[]
+ */
+ public function validateScopes($scopes, $redirectUri = null)
+ {
+ if ($scopes === null) {
+ $scopes = [];
+ } elseif (\is_string($scopes)) {
+ $scopes = $this->convertScopesQueryStringToArray($scopes);
+ }
+
+ if (!\is_array($scopes)) {
+ throw OAuthServerException::invalidRequest('scope');
+ }
+
+ $validScopes = [];
+
+ foreach ($scopes as $scopeItem) {
+ $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
+
+ if ($scope instanceof ScopeEntityInterface === false) {
+ throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
+ }
+
+ $validScopes[] = $scope;
+ }
+
+ return $validScopes;
+ }
+
+ /**
+ * Converts a scopes query string to an array to easily iterate for validation.
+ *
+ * @param string $scopes
+ *
+ * @return array
+ */
+ private function convertScopesQueryStringToArray(string $scopes)
+ {
+ return \array_filter(\explode(self::SCOPE_DELIMITER_STRING, \trim($scopes)), function ($scope) {
+ return $scope !== '';
+ });
+ }
+
+ /**
+ * Retrieve request parameter.
+ *
+ * @param string $parameter
+ * @param ServerRequestInterface $request
+ * @param mixed $default
+ *
+ * @return null|string
+ */
+ protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null)
+ {
+ $requestParameters = (array) $request->getParsedBody();
+
+ return $requestParameters[$parameter] ?? $default;
+ }
+
+ /**
+ * Retrieve HTTP Basic Auth credentials with the Authorization header
+ * of a request. First index of the returned array is the username,
+ * second is the password (so list() will work). If the header does
+ * not exist, or is otherwise an invalid HTTP Basic header, return
+ * [null, null].
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @return string[]|null[]
+ */
+ protected function getBasicAuthCredentials(ServerRequestInterface $request)
+ {
+ if (!$request->hasHeader('Authorization')) {
+ return [null, null];
+ }
+
+ $header = $request->getHeader('Authorization')[0];
+ if (\strpos($header, 'Basic ') !== 0) {
+ return [null, null];
+ }
+
+ if (!($decoded = \base64_decode(\substr($header, 6)))) {
+ return [null, null];
+ }
+
+ if (\strpos($decoded, ':') === false) {
+ return [null, null]; // HTTP Basic header without colon isn't valid
+ }
+
+ return \explode(':', $decoded, 2);
+ }
+
+ /**
+ * Retrieve query string parameter.
+ *
+ * @param string $parameter
+ * @param ServerRequestInterface $request
+ * @param mixed $default
+ *
+ * @return null|string
+ */
+ protected function getQueryStringParameter($parameter, ServerRequestInterface $request, $default = null)
+ {
+ return isset($request->getQueryParams()[$parameter]) ? $request->getQueryParams()[$parameter] : $default;
+ }
+
+ /**
+ * Retrieve cookie parameter.
+ *
+ * @param string $parameter
+ * @param ServerRequestInterface $request
+ * @param mixed $default
+ *
+ * @return null|string
+ */
+ protected function getCookieParameter($parameter, ServerRequestInterface $request, $default = null)
+ {
+ return isset($request->getCookieParams()[$parameter]) ? $request->getCookieParams()[$parameter] : $default;
+ }
+
+ /**
+ * Retrieve server parameter.
+ *
+ * @param string $parameter
+ * @param ServerRequestInterface $request
+ * @param mixed $default
+ *
+ * @return null|string
+ */
+ protected function getServerParameter($parameter, ServerRequestInterface $request, $default = null)
+ {
+ return isset($request->getServerParams()[$parameter]) ? $request->getServerParams()[$parameter] : $default;
+ }
+
+ /**
+ * Issue an access token.
+ *
+ * @param DateInterval $accessTokenTTL
+ * @param ClientEntityInterface $client
+ * @param string|null $userIdentifier
+ * @param ScopeEntityInterface[] $scopes
+ *
+ * @throws OAuthServerException
+ * @throws UniqueTokenIdentifierConstraintViolationException
+ *
+ * @return AccessTokenEntityInterface
+ */
+ protected function issueAccessToken(
+ DateInterval $accessTokenTTL,
+ ClientEntityInterface $client,
+ $userIdentifier,
+ array $scopes = []
+ ) {
+ $maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
+
+ $accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
+ $accessToken->setExpiryDateTime((new DateTimeImmutable())->add($accessTokenTTL));
+ $accessToken->setPrivateKey($this->privateKey);
+
+ while ($maxGenerationAttempts-- > 0) {
+ $accessToken->setIdentifier($this->generateUniqueIdentifier());
+ try {
+ $this->accessTokenRepository->persistNewAccessToken($accessToken);
+
+ return $accessToken;
+ } catch (UniqueTokenIdentifierConstraintViolationException $e) {
+ if ($maxGenerationAttempts === 0) {
+ throw $e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Issue an auth code.
+ *
+ * @param DateInterval $authCodeTTL
+ * @param ClientEntityInterface $client
+ * @param string $userIdentifier
+ * @param string|null $redirectUri
+ * @param ScopeEntityInterface[] $scopes
+ *
+ * @throws OAuthServerException
+ * @throws UniqueTokenIdentifierConstraintViolationException
+ *
+ * @return AuthCodeEntityInterface
+ */
+ protected function issueAuthCode(
+ DateInterval $authCodeTTL,
+ ClientEntityInterface $client,
+ $userIdentifier,
+ $redirectUri,
+ array $scopes = []
+ ) {
+ $maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
+
+ $authCode = $this->authCodeRepository->getNewAuthCode();
+ $authCode->setExpiryDateTime((new DateTimeImmutable())->add($authCodeTTL));
+ $authCode->setClient($client);
+ $authCode->setUserIdentifier($userIdentifier);
+
+ if ($redirectUri !== null) {
+ $authCode->setRedirectUri($redirectUri);
+ }
+
+ foreach ($scopes as $scope) {
+ $authCode->addScope($scope);
+ }
+
+ while ($maxGenerationAttempts-- > 0) {
+ $authCode->setIdentifier($this->generateUniqueIdentifier());
+ try {
+ $this->authCodeRepository->persistNewAuthCode($authCode);
+
+ return $authCode;
+ } catch (UniqueTokenIdentifierConstraintViolationException $e) {
+ if ($maxGenerationAttempts === 0) {
+ throw $e;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param AccessTokenEntityInterface $accessToken
+ *
+ * @throws OAuthServerException
+ * @throws UniqueTokenIdentifierConstraintViolationException
+ *
+ * @return RefreshTokenEntityInterface|null
+ */
+ protected function issueRefreshToken(AccessTokenEntityInterface $accessToken)
+ {
+ $refreshToken = $this->refreshTokenRepository->getNewRefreshToken();
+
+ if ($refreshToken === null) {
+ return null;
+ }
+
+ $refreshToken->setExpiryDateTime((new DateTimeImmutable())->add($this->refreshTokenTTL));
+ $refreshToken->setAccessToken($accessToken);
+
+ $maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
+
+ while ($maxGenerationAttempts-- > 0) {
+ $refreshToken->setIdentifier($this->generateUniqueIdentifier());
+ try {
+ $this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
+
+ return $refreshToken;
+ } catch (UniqueTokenIdentifierConstraintViolationException $e) {
+ if ($maxGenerationAttempts === 0) {
+ throw $e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Generate a new unique identifier.
+ *
+ * @param int $length
+ *
+ * @throws OAuthServerException
+ *
+ * @return string
+ */
+ protected function generateUniqueIdentifier($length = 40)
+ {
+ try {
+ return \bin2hex(\random_bytes($length));
+ // @codeCoverageIgnoreStart
+ } catch (TypeError $e) {
+ throw OAuthServerException::serverError('An unexpected error has occurred', $e);
+ } catch (Error $e) {
+ throw OAuthServerException::serverError('An unexpected error has occurred', $e);
+ } catch (Exception $e) {
+ // If you get this message, the CSPRNG failed hard.
+ throw OAuthServerException::serverError('Could not generate a random string', $e);
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canRespondToAccessTokenRequest(ServerRequestInterface $request)
+ {
+ $requestParameters = (array) $request->getParsedBody();
+
+ return (
+ \array_key_exists('grant_type', $requestParameters)
+ && $requestParameters['grant_type'] === $this->getIdentifier()
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateAuthorizationRequest(ServerRequestInterface $request)
+ {
+ throw new LogicException('This grant cannot validate an authorization request');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest)
+ {
+ throw new LogicException('This grant cannot complete an authorization request');
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/AuthCodeGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/AuthCodeGrant.php
new file mode 100644
index 0000000..9d6e63d
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/AuthCodeGrant.php
@@ -0,0 +1,424 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use DateTimeImmutable;
+use Exception;
+use League\OAuth2\Server\CodeChallengeVerifiers\CodeChallengeVerifierInterface;
+use League\OAuth2\Server\CodeChallengeVerifiers\PlainVerifier;
+use League\OAuth2\Server\CodeChallengeVerifiers\S256Verifier;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\UserEntityInterface;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
+use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
+use League\OAuth2\Server\RequestAccessTokenEvent;
+use League\OAuth2\Server\RequestEvent;
+use League\OAuth2\Server\RequestRefreshTokenEvent;
+use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
+use League\OAuth2\Server\ResponseTypes\RedirectResponse;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use LogicException;
+use Psr\Http\Message\ServerRequestInterface;
+use stdClass;
+
+class AuthCodeGrant extends AbstractAuthorizeGrant
+{
+ /**
+ * @var DateInterval
+ */
+ private $authCodeTTL;
+
+ /**
+ * @var bool
+ */
+ private $requireCodeChallengeForPublicClients = true;
+
+ /**
+ * @var CodeChallengeVerifierInterface[]
+ */
+ private $codeChallengeVerifiers = [];
+
+ /**
+ * @param AuthCodeRepositoryInterface $authCodeRepository
+ * @param RefreshTokenRepositoryInterface $refreshTokenRepository
+ * @param DateInterval $authCodeTTL
+ *
+ * @throws Exception
+ */
+ public function __construct(
+ AuthCodeRepositoryInterface $authCodeRepository,
+ RefreshTokenRepositoryInterface $refreshTokenRepository,
+ DateInterval $authCodeTTL
+ ) {
+ $this->setAuthCodeRepository($authCodeRepository);
+ $this->setRefreshTokenRepository($refreshTokenRepository);
+ $this->authCodeTTL = $authCodeTTL;
+ $this->refreshTokenTTL = new DateInterval('P1M');
+
+ if (\in_array('sha256', \hash_algos(), true)) {
+ $s256Verifier = new S256Verifier();
+ $this->codeChallengeVerifiers[$s256Verifier->getMethod()] = $s256Verifier;
+ }
+
+ $plainVerifier = new PlainVerifier();
+ $this->codeChallengeVerifiers[$plainVerifier->getMethod()] = $plainVerifier;
+ }
+
+ /**
+ * Disable the requirement for a code challenge for public clients.
+ */
+ public function disableRequireCodeChallengeForPublicClients()
+ {
+ $this->requireCodeChallengeForPublicClients = false;
+ }
+
+ /**
+ * Respond to an access token request.
+ *
+ * @param ServerRequestInterface $request
+ * @param ResponseTypeInterface $responseType
+ * @param DateInterval $accessTokenTTL
+ *
+ * @throws OAuthServerException
+ *
+ * @return ResponseTypeInterface
+ */
+ public function respondToAccessTokenRequest(
+ ServerRequestInterface $request,
+ ResponseTypeInterface $responseType,
+ DateInterval $accessTokenTTL
+ ) {
+ list($clientId) = $this->getClientCredentials($request);
+
+ $client = $this->getClientEntityOrFail($clientId, $request);
+
+ // Only validate the client if it is confidential
+ if ($client->isConfidential()) {
+ $this->validateClient($request);
+ }
+
+ $encryptedAuthCode = $this->getRequestParameter('code', $request, null);
+
+ if (!\is_string($encryptedAuthCode)) {
+ throw OAuthServerException::invalidRequest('code');
+ }
+
+ try {
+ $authCodePayload = \json_decode($this->decrypt($encryptedAuthCode));
+
+ $this->validateAuthorizationCode($authCodePayload, $client, $request);
+
+ $scopes = $this->scopeRepository->finalizeScopes(
+ $this->validateScopes($authCodePayload->scopes),
+ $this->getIdentifier(),
+ $client,
+ $authCodePayload->user_id
+ );
+ } catch (LogicException $e) {
+ throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code', $e);
+ }
+
+ $codeVerifier = $this->getRequestParameter('code_verifier', $request, null);
+
+ // If a code challenge isn't present but a code verifier is, reject the request to block PKCE downgrade attack
+ if (empty($authCodePayload->code_challenge) && $codeVerifier !== null) {
+ throw OAuthServerException::invalidRequest(
+ 'code_challenge',
+ 'code_verifier received when no code_challenge is present'
+ );
+ }
+
+ if (!empty($authCodePayload->code_challenge)) {
+ $this->validateCodeChallenge($authCodePayload, $codeVerifier);
+ }
+
+ // Issue and persist new access token
+ $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
+ $this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
+ $responseType->setAccessToken($accessToken);
+
+ // Issue and persist new refresh token if given
+ $refreshToken = $this->issueRefreshToken($accessToken);
+
+ if ($refreshToken !== null) {
+ $this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken));
+ $responseType->setRefreshToken($refreshToken);
+ }
+
+ // Revoke used auth code
+ $this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id);
+
+ return $responseType;
+ }
+
+ private function validateCodeChallenge($authCodePayload, $codeVerifier)
+ {
+ if ($codeVerifier === null) {
+ throw OAuthServerException::invalidRequest('code_verifier');
+ }
+
+ // Validate code_verifier according to RFC-7636
+ // @see: https://tools.ietf.org/html/rfc7636#section-4.1
+ if (\preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeVerifier) !== 1) {
+ throw OAuthServerException::invalidRequest(
+ 'code_verifier',
+ 'Code Verifier must follow the specifications of RFC-7636.'
+ );
+ }
+
+ if (\property_exists($authCodePayload, 'code_challenge_method')) {
+ if (isset($this->codeChallengeVerifiers[$authCodePayload->code_challenge_method])) {
+ $codeChallengeVerifier = $this->codeChallengeVerifiers[$authCodePayload->code_challenge_method];
+
+ if ($codeChallengeVerifier->verifyCodeChallenge($codeVerifier, $authCodePayload->code_challenge) === false) {
+ throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.');
+ }
+ } else {
+ throw OAuthServerException::serverError(
+ \sprintf(
+ 'Unsupported code challenge method `%s`',
+ $authCodePayload->code_challenge_method
+ )
+ );
+ }
+ }
+ }
+
+ /**
+ * Validate the authorization code.
+ *
+ * @param stdClass $authCodePayload
+ * @param ClientEntityInterface $client
+ * @param ServerRequestInterface $request
+ */
+ private function validateAuthorizationCode(
+ $authCodePayload,
+ ClientEntityInterface $client,
+ ServerRequestInterface $request
+ ) {
+ if (!\property_exists($authCodePayload, 'auth_code_id')) {
+ throw OAuthServerException::invalidRequest('code', 'Authorization code malformed');
+ }
+
+ if (\time() > $authCodePayload->expire_time) {
+ throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
+ }
+
+ if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
+ throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
+ }
+
+ if ($authCodePayload->client_id !== $client->getIdentifier()) {
+ throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client');
+ }
+
+ // The redirect URI is required in this request
+ $redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
+ if (empty($authCodePayload->redirect_uri) === false && $redirectUri === null) {
+ throw OAuthServerException::invalidRequest('redirect_uri');
+ }
+
+ if ($authCodePayload->redirect_uri !== $redirectUri) {
+ throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI');
+ }
+ }
+
+ /**
+ * Return the grant identifier that can be used in matching up requests.
+ *
+ * @return string
+ */
+ public function getIdentifier()
+ {
+ return 'authorization_code';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
+ {
+ return (
+ \array_key_exists('response_type', $request->getQueryParams())
+ && $request->getQueryParams()['response_type'] === 'code'
+ && isset($request->getQueryParams()['client_id'])
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateAuthorizationRequest(ServerRequestInterface $request)
+ {
+ $clientId = $this->getQueryStringParameter(
+ 'client_id',
+ $request,
+ $this->getServerParameter('PHP_AUTH_USER', $request)
+ );
+
+ if ($clientId === null) {
+ throw OAuthServerException::invalidRequest('client_id');
+ }
+
+ $client = $this->getClientEntityOrFail($clientId, $request);
+
+ $redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
+
+ if ($redirectUri !== null) {
+ if (!\is_string($redirectUri)) {
+ throw OAuthServerException::invalidRequest('redirect_uri');
+ }
+
+ $this->validateRedirectUri($redirectUri, $client, $request);
+ } elseif (empty($client->getRedirectUri()) ||
+ (\is_array($client->getRedirectUri()) && \count($client->getRedirectUri()) !== 1)) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
+
+ throw OAuthServerException::invalidClient($request);
+ }
+
+ $defaultClientRedirectUri = \is_array($client->getRedirectUri())
+ ? $client->getRedirectUri()[0]
+ : $client->getRedirectUri();
+
+ $scopes = $this->validateScopes(
+ $this->getQueryStringParameter('scope', $request, $this->defaultScope),
+ $redirectUri ?? $defaultClientRedirectUri
+ );
+
+ $stateParameter = $this->getQueryStringParameter('state', $request);
+
+ $authorizationRequest = new AuthorizationRequest();
+ $authorizationRequest->setGrantTypeId($this->getIdentifier());
+ $authorizationRequest->setClient($client);
+ $authorizationRequest->setRedirectUri($redirectUri);
+
+ if ($stateParameter !== null) {
+ $authorizationRequest->setState($stateParameter);
+ }
+
+ $authorizationRequest->setScopes($scopes);
+
+ $codeChallenge = $this->getQueryStringParameter('code_challenge', $request);
+
+ if ($codeChallenge !== null) {
+ $codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
+
+ if (\array_key_exists($codeChallengeMethod, $this->codeChallengeVerifiers) === false) {
+ throw OAuthServerException::invalidRequest(
+ 'code_challenge_method',
+ 'Code challenge method must be one of ' . \implode(', ', \array_map(
+ function ($method) {
+ return '`' . $method . '`';
+ },
+ \array_keys($this->codeChallengeVerifiers)
+ ))
+ );
+ }
+
+ // Validate code_challenge according to RFC-7636
+ // @see: https://tools.ietf.org/html/rfc7636#section-4.2
+ if (\preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeChallenge) !== 1) {
+ throw OAuthServerException::invalidRequest(
+ 'code_challenge',
+ 'Code challenge must follow the specifications of RFC-7636.'
+ );
+ }
+
+ $authorizationRequest->setCodeChallenge($codeChallenge);
+ $authorizationRequest->setCodeChallengeMethod($codeChallengeMethod);
+ } elseif ($this->requireCodeChallengeForPublicClients && !$client->isConfidential()) {
+ throw OAuthServerException::invalidRequest('code_challenge', 'Code challenge must be provided for public clients');
+ }
+
+ return $authorizationRequest;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest)
+ {
+ if ($authorizationRequest->getUser() instanceof UserEntityInterface === false) {
+ throw new LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest');
+ }
+
+ $finalRedirectUri = $authorizationRequest->getRedirectUri()
+ ?? $this->getClientRedirectUri($authorizationRequest);
+
+ // The user approved the client, redirect them back with an auth code
+ if ($authorizationRequest->isAuthorizationApproved() === true) {
+ $authCode = $this->issueAuthCode(
+ $this->authCodeTTL,
+ $authorizationRequest->getClient(),
+ $authorizationRequest->getUser()->getIdentifier(),
+ $authorizationRequest->getRedirectUri(),
+ $authorizationRequest->getScopes()
+ );
+
+ $payload = [
+ 'client_id' => $authCode->getClient()->getIdentifier(),
+ 'redirect_uri' => $authCode->getRedirectUri(),
+ 'auth_code_id' => $authCode->getIdentifier(),
+ 'scopes' => $authCode->getScopes(),
+ 'user_id' => $authCode->getUserIdentifier(),
+ 'expire_time' => (new DateTimeImmutable())->add($this->authCodeTTL)->getTimestamp(),
+ 'code_challenge' => $authorizationRequest->getCodeChallenge(),
+ 'code_challenge_method' => $authorizationRequest->getCodeChallengeMethod(),
+ ];
+
+ $jsonPayload = \json_encode($payload);
+
+ if ($jsonPayload === false) {
+ throw new LogicException('An error was encountered when JSON encoding the authorization request response');
+ }
+
+ $response = new RedirectResponse();
+ $response->setRedirectUri(
+ $this->makeRedirectUri(
+ $finalRedirectUri,
+ [
+ 'code' => $this->encrypt($jsonPayload),
+ 'state' => $authorizationRequest->getState(),
+ ]
+ )
+ );
+
+ return $response;
+ }
+
+ // The user denied the client, redirect them back with an error
+ throw OAuthServerException::accessDenied(
+ 'The user denied the request',
+ $this->makeRedirectUri(
+ $finalRedirectUri,
+ [
+ 'state' => $authorizationRequest->getState(),
+ ]
+ )
+ );
+ }
+
+ /**
+ * Get the client redirect URI if not set in the request.
+ *
+ * @param AuthorizationRequest $authorizationRequest
+ *
+ * @return string
+ */
+ private function getClientRedirectUri(AuthorizationRequest $authorizationRequest)
+ {
+ return \is_array($authorizationRequest->getClient()->getRedirectUri())
+ ? $authorizationRequest->getClient()->getRedirectUri()[0]
+ : $authorizationRequest->getClient()->getRedirectUri();
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/ClientCredentialsGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/ClientCredentialsGrant.php
new file mode 100644
index 0000000..d342b26
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/ClientCredentialsGrant.php
@@ -0,0 +1,71 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\RequestAccessTokenEvent;
+use League\OAuth2\Server\RequestEvent;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Client credentials grant class.
+ */
+class ClientCredentialsGrant extends AbstractGrant
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function respondToAccessTokenRequest(
+ ServerRequestInterface $request,
+ ResponseTypeInterface $responseType,
+ DateInterval $accessTokenTTL
+ ) {
+ list($clientId) = $this->getClientCredentials($request);
+
+ $client = $this->getClientEntityOrFail($clientId, $request);
+
+ if (!$client->isConfidential()) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
+
+ throw OAuthServerException::invalidClient($request);
+ }
+
+ // Validate request
+ $this->validateClient($request);
+
+ $scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));
+
+ // Finalize the requested scopes
+ $finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);
+
+ // Issue and persist access token
+ $accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes);
+
+ // Send event to emitter
+ $this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
+
+ // Inject access token into response type
+ $responseType->setAccessToken($accessToken);
+
+ return $responseType;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIdentifier()
+ {
+ return 'client_credentials';
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/GrantTypeInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/GrantTypeInterface.php
new file mode 100644
index 0000000..41ebeb5
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/GrantTypeInterface.php
@@ -0,0 +1,144 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use Defuse\Crypto\Key;
+use League\Event\EmitterAwareInterface;
+use League\OAuth2\Server\CryptKey;
+use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
+use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
+use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
+use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Grant type interface.
+ */
+interface GrantTypeInterface extends EmitterAwareInterface
+{
+ /**
+ * Set refresh token TTL.
+ *
+ * @param DateInterval $refreshTokenTTL
+ */
+ public function setRefreshTokenTTL(DateInterval $refreshTokenTTL);
+
+ /**
+ * Return the grant identifier that can be used in matching up requests.
+ *
+ * @return string
+ */
+ public function getIdentifier();
+
+ /**
+ * Respond to an incoming request.
+ *
+ * @param ServerRequestInterface $request
+ * @param ResponseTypeInterface $responseType
+ * @param DateInterval $accessTokenTTL
+ *
+ * @return ResponseTypeInterface
+ */
+ public function respondToAccessTokenRequest(
+ ServerRequestInterface $request,
+ ResponseTypeInterface $responseType,
+ DateInterval $accessTokenTTL
+ );
+
+ /**
+ * The grant type should return true if it is able to response to an authorization request
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @return bool
+ */
+ public function canRespondToAuthorizationRequest(ServerRequestInterface $request);
+
+ /**
+ * If the grant can respond to an authorization request this method should be called to validate the parameters of
+ * the request.
+ *
+ * If the validation is successful an AuthorizationRequest object will be returned. This object can be safely
+ * serialized in a user's session, and can be used during user authentication and authorization.
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @return AuthorizationRequest
+ */
+ public function validateAuthorizationRequest(ServerRequestInterface $request);
+
+ /**
+ * Once a user has authenticated and authorized the client the grant can complete the authorization request.
+ * The AuthorizationRequest object's $userId property must be set to the authenticated user and the
+ * $authorizationApproved property must reflect their desire to authorize or deny the client.
+ *
+ * @param AuthorizationRequest $authorizationRequest
+ *
+ * @return ResponseTypeInterface
+ */
+ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest);
+
+ /**
+ * The grant type should return true if it is able to respond to this request.
+ *
+ * For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property.
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @return bool
+ */
+ public function canRespondToAccessTokenRequest(ServerRequestInterface $request);
+
+ /**
+ * Set the client repository.
+ *
+ * @param ClientRepositoryInterface $clientRepository
+ */
+ public function setClientRepository(ClientRepositoryInterface $clientRepository);
+
+ /**
+ * Set the access token repository.
+ *
+ * @param AccessTokenRepositoryInterface $accessTokenRepository
+ */
+ public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository);
+
+ /**
+ * Set the scope repository.
+ *
+ * @param ScopeRepositoryInterface $scopeRepository
+ */
+ public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);
+
+ /**
+ * Set the default scope.
+ *
+ * @param string $scope
+ */
+ public function setDefaultScope($scope);
+
+ /**
+ * Set the path to the private key.
+ *
+ * @param CryptKey $privateKey
+ */
+ public function setPrivateKey(CryptKey $privateKey);
+
+ /**
+ * Set the encryption key
+ *
+ * @param string|Key|null $key
+ */
+ public function setEncryptionKey($key = null);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/ImplicitGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/ImplicitGrant.php
new file mode 100644
index 0000000..0229dd9
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/ImplicitGrant.php
@@ -0,0 +1,232 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use League\OAuth2\Server\Entities\UserEntityInterface;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
+use League\OAuth2\Server\RequestEvent;
+use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
+use League\OAuth2\Server\ResponseTypes\RedirectResponse;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use LogicException;
+use Psr\Http\Message\ServerRequestInterface;
+
+class ImplicitGrant extends AbstractAuthorizeGrant
+{
+ /**
+ * @var DateInterval
+ */
+ private $accessTokenTTL;
+
+ /**
+ * @var string
+ */
+ private $queryDelimiter;
+
+ /**
+ * @param DateInterval $accessTokenTTL
+ * @param string $queryDelimiter
+ */
+ public function __construct(DateInterval $accessTokenTTL, $queryDelimiter = '#')
+ {
+ $this->accessTokenTTL = $accessTokenTTL;
+ $this->queryDelimiter = $queryDelimiter;
+ }
+
+ /**
+ * @param DateInterval $refreshTokenTTL
+ *
+ * @throw LogicException
+ */
+ public function setRefreshTokenTTL(DateInterval $refreshTokenTTL)
+ {
+ throw new LogicException('The Implicit Grant does not return refresh tokens');
+ }
+
+ /**
+ * @param RefreshTokenRepositoryInterface $refreshTokenRepository
+ *
+ * @throw LogicException
+ */
+ public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
+ {
+ throw new LogicException('The Implicit Grant does not return refresh tokens');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canRespondToAccessTokenRequest(ServerRequestInterface $request)
+ {
+ return false;
+ }
+
+ /**
+ * Return the grant identifier that can be used in matching up requests.
+ *
+ * @return string
+ */
+ public function getIdentifier()
+ {
+ return 'implicit';
+ }
+
+ /**
+ * Respond to an incoming request.
+ *
+ * @param ServerRequestInterface $request
+ * @param ResponseTypeInterface $responseType
+ * @param DateInterval $accessTokenTTL
+ *
+ * @return ResponseTypeInterface
+ */
+ public function respondToAccessTokenRequest(
+ ServerRequestInterface $request,
+ ResponseTypeInterface $responseType,
+ DateInterval $accessTokenTTL
+ ) {
+ throw new LogicException('This grant does not used this method');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
+ {
+ return (
+ isset($request->getQueryParams()['response_type'])
+ && $request->getQueryParams()['response_type'] === 'token'
+ && isset($request->getQueryParams()['client_id'])
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateAuthorizationRequest(ServerRequestInterface $request)
+ {
+ $clientId = $this->getQueryStringParameter(
+ 'client_id',
+ $request,
+ $this->getServerParameter('PHP_AUTH_USER', $request)
+ );
+
+ if (\is_null($clientId)) {
+ throw OAuthServerException::invalidRequest('client_id');
+ }
+
+ $client = $this->getClientEntityOrFail($clientId, $request);
+
+ $redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
+
+ if ($redirectUri !== null) {
+ if (!\is_string($redirectUri)) {
+ throw OAuthServerException::invalidRequest('redirect_uri');
+ }
+
+ $this->validateRedirectUri($redirectUri, $client, $request);
+ } elseif (\is_array($client->getRedirectUri()) && \count($client->getRedirectUri()) !== 1
+ || empty($client->getRedirectUri())) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
+ throw OAuthServerException::invalidClient($request);
+ } else {
+ $redirectUri = \is_array($client->getRedirectUri())
+ ? $client->getRedirectUri()[0]
+ : $client->getRedirectUri();
+ }
+
+ $scopes = $this->validateScopes(
+ $this->getQueryStringParameter('scope', $request, $this->defaultScope),
+ $redirectUri
+ );
+
+ $stateParameter = $this->getQueryStringParameter('state', $request);
+
+ if ($stateParameter !== null && !\is_string($stateParameter)) {
+ throw OAuthServerException::invalidRequest('state');
+ }
+
+ $authorizationRequest = new AuthorizationRequest();
+ $authorizationRequest->setGrantTypeId($this->getIdentifier());
+ $authorizationRequest->setClient($client);
+ $authorizationRequest->setRedirectUri($redirectUri);
+
+ if ($stateParameter !== null) {
+ $authorizationRequest->setState($stateParameter);
+ }
+
+ $authorizationRequest->setScopes($scopes);
+
+ return $authorizationRequest;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest)
+ {
+ if ($authorizationRequest->getUser() instanceof UserEntityInterface === false) {
+ throw new LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest');
+ }
+
+ $finalRedirectUri = ($authorizationRequest->getRedirectUri() === null)
+ ? \is_array($authorizationRequest->getClient()->getRedirectUri())
+ ? $authorizationRequest->getClient()->getRedirectUri()[0]
+ : $authorizationRequest->getClient()->getRedirectUri()
+ : $authorizationRequest->getRedirectUri();
+
+ // The user approved the client, redirect them back with an access token
+ if ($authorizationRequest->isAuthorizationApproved() === true) {
+ // Finalize the requested scopes
+ $finalizedScopes = $this->scopeRepository->finalizeScopes(
+ $authorizationRequest->getScopes(),
+ $this->getIdentifier(),
+ $authorizationRequest->getClient(),
+ $authorizationRequest->getUser()->getIdentifier()
+ );
+
+ $accessToken = $this->issueAccessToken(
+ $this->accessTokenTTL,
+ $authorizationRequest->getClient(),
+ $authorizationRequest->getUser()->getIdentifier(),
+ $finalizedScopes
+ );
+
+ $response = new RedirectResponse();
+ $response->setRedirectUri(
+ $this->makeRedirectUri(
+ $finalRedirectUri,
+ [
+ 'access_token' => (string) $accessToken,
+ 'token_type' => 'Bearer',
+ 'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - \time(),
+ 'state' => $authorizationRequest->getState(),
+ ],
+ $this->queryDelimiter
+ )
+ );
+
+ return $response;
+ }
+
+ // The user denied the client, redirect them back with an error
+ throw OAuthServerException::accessDenied(
+ 'The user denied the request',
+ $this->makeRedirectUri(
+ $finalRedirectUri,
+ [
+ 'state' => $authorizationRequest->getState(),
+ ]
+ )
+ );
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/PasswordGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/PasswordGrant.php
new file mode 100644
index 0000000..fd32d26
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/PasswordGrant.php
@@ -0,0 +1,122 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\UserEntityInterface;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
+use League\OAuth2\Server\Repositories\UserRepositoryInterface;
+use League\OAuth2\Server\RequestAccessTokenEvent;
+use League\OAuth2\Server\RequestEvent;
+use League\OAuth2\Server\RequestRefreshTokenEvent;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Password grant class.
+ */
+class PasswordGrant extends AbstractGrant
+{
+ /**
+ * @param UserRepositoryInterface $userRepository
+ * @param RefreshTokenRepositoryInterface $refreshTokenRepository
+ */
+ public function __construct(
+ UserRepositoryInterface $userRepository,
+ RefreshTokenRepositoryInterface $refreshTokenRepository
+ ) {
+ $this->setUserRepository($userRepository);
+ $this->setRefreshTokenRepository($refreshTokenRepository);
+
+ $this->refreshTokenTTL = new DateInterval('P1M');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function respondToAccessTokenRequest(
+ ServerRequestInterface $request,
+ ResponseTypeInterface $responseType,
+ DateInterval $accessTokenTTL
+ ) {
+ // Validate request
+ $client = $this->validateClient($request);
+ $scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));
+ $user = $this->validateUser($request, $client);
+
+ // Finalize the requested scopes
+ $finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
+
+ // Issue and persist new access token
+ $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
+ $this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
+ $responseType->setAccessToken($accessToken);
+
+ // Issue and persist new refresh token if given
+ $refreshToken = $this->issueRefreshToken($accessToken);
+
+ if ($refreshToken !== null) {
+ $this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken));
+ $responseType->setRefreshToken($refreshToken);
+ }
+
+ return $responseType;
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @param ClientEntityInterface $client
+ *
+ * @throws OAuthServerException
+ *
+ * @return UserEntityInterface
+ */
+ protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
+ {
+ $username = $this->getRequestParameter('username', $request);
+
+ if (!\is_string($username)) {
+ throw OAuthServerException::invalidRequest('username');
+ }
+
+ $password = $this->getRequestParameter('password', $request);
+
+ if (!\is_string($password)) {
+ throw OAuthServerException::invalidRequest('password');
+ }
+
+ $user = $this->userRepository->getUserEntityByUserCredentials(
+ $username,
+ $password,
+ $this->getIdentifier(),
+ $client
+ );
+
+ if ($user instanceof UserEntityInterface === false) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
+
+ throw OAuthServerException::invalidCredentials();
+ }
+
+ return $user;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIdentifier()
+ {
+ return 'password';
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Grant/RefreshTokenGrant.php b/api_candidatos/vendor/league/oauth2-server/src/Grant/RefreshTokenGrant.php
new file mode 100644
index 0000000..2dedf15
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Grant/RefreshTokenGrant.php
@@ -0,0 +1,136 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Grant;
+
+use DateInterval;
+use Exception;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
+use League\OAuth2\Server\RequestAccessTokenEvent;
+use League\OAuth2\Server\RequestEvent;
+use League\OAuth2\Server\RequestRefreshTokenEvent;
+use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Refresh token grant.
+ */
+class RefreshTokenGrant extends AbstractGrant
+{
+ /**
+ * @param RefreshTokenRepositoryInterface $refreshTokenRepository
+ */
+ public function __construct(RefreshTokenRepositoryInterface $refreshTokenRepository)
+ {
+ $this->setRefreshTokenRepository($refreshTokenRepository);
+
+ $this->refreshTokenTTL = new DateInterval('P1M');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function respondToAccessTokenRequest(
+ ServerRequestInterface $request,
+ ResponseTypeInterface $responseType,
+ DateInterval $accessTokenTTL
+ ) {
+ // Validate request
+ $client = $this->validateClient($request);
+ $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
+ $scopes = $this->validateScopes(
+ $this->getRequestParameter(
+ 'scope',
+ $request,
+ \implode(self::SCOPE_DELIMITER_STRING, $oldRefreshToken['scopes'])
+ )
+ );
+
+ // The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
+ // the request doesn't include any new scopes
+ foreach ($scopes as $scope) {
+ if (\in_array($scope->getIdentifier(), $oldRefreshToken['scopes'], true) === false) {
+ throw OAuthServerException::invalidScope($scope->getIdentifier());
+ }
+ }
+
+ // Expire old tokens
+ $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
+ if ($this->revokeRefreshTokens) {
+ $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
+ }
+
+ // Issue and persist new access token
+ $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
+ $this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
+ $responseType->setAccessToken($accessToken);
+
+ // Issue and persist new refresh token if given
+ if ($this->revokeRefreshTokens) {
+ $refreshToken = $this->issueRefreshToken($accessToken);
+
+ if ($refreshToken !== null) {
+ $this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken));
+ $responseType->setRefreshToken($refreshToken);
+ }
+ }
+
+ return $responseType;
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @param string $clientId
+ *
+ * @throws OAuthServerException
+ *
+ * @return array
+ */
+ protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId)
+ {
+ $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request);
+ if (!\is_string($encryptedRefreshToken)) {
+ throw OAuthServerException::invalidRequest('refresh_token');
+ }
+
+ // Validate refresh token
+ try {
+ $refreshToken = $this->decrypt($encryptedRefreshToken);
+ } catch (Exception $e) {
+ throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token', $e);
+ }
+
+ $refreshTokenData = \json_decode($refreshToken, true);
+ if ($refreshTokenData['client_id'] !== $clientId) {
+ $this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_CLIENT_FAILED, $request));
+ throw OAuthServerException::invalidRefreshToken('Token is not linked to client');
+ }
+
+ if ($refreshTokenData['expire_time'] < \time()) {
+ throw OAuthServerException::invalidRefreshToken('Token has expired');
+ }
+
+ if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) {
+ throw OAuthServerException::invalidRefreshToken('Token has been revoked');
+ }
+
+ return $refreshTokenData;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIdentifier()
+ {
+ return 'refresh_token';
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Middleware/AuthorizationServerMiddleware.php b/api_candidatos/vendor/league/oauth2-server/src/Middleware/AuthorizationServerMiddleware.php
new file mode 100644
index 0000000..9b78b45
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Middleware/AuthorizationServerMiddleware.php
@@ -0,0 +1,56 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Middleware;
+
+use Exception;
+use League\OAuth2\Server\AuthorizationServer;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class AuthorizationServerMiddleware
+{
+ /**
+ * @var AuthorizationServer
+ */
+ private $server;
+
+ /**
+ * @param AuthorizationServer $server
+ */
+ public function __construct(AuthorizationServer $server)
+ {
+ $this->server = $server;
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ * @param callable $next
+ *
+ * @return ResponseInterface
+ */
+ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
+ {
+ try {
+ $response = $this->server->respondToAccessTokenRequest($request, $response);
+ } catch (OAuthServerException $exception) {
+ return $exception->generateHttpResponse($response);
+ // @codeCoverageIgnoreStart
+ } catch (Exception $exception) {
+ return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500))
+ ->generateHttpResponse($response);
+ // @codeCoverageIgnoreEnd
+ }
+
+ // Pass the request and response on to the next responder in the chain
+ return $next($request, $response);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Middleware/ResourceServerMiddleware.php b/api_candidatos/vendor/league/oauth2-server/src/Middleware/ResourceServerMiddleware.php
new file mode 100644
index 0000000..e152a99
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Middleware/ResourceServerMiddleware.php
@@ -0,0 +1,56 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Middleware;
+
+use Exception;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\ResourceServer;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class ResourceServerMiddleware
+{
+ /**
+ * @var ResourceServer
+ */
+ private $server;
+
+ /**
+ * @param ResourceServer $server
+ */
+ public function __construct(ResourceServer $server)
+ {
+ $this->server = $server;
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ * @param callable $next
+ *
+ * @return ResponseInterface
+ */
+ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
+ {
+ try {
+ $request = $this->server->validateAuthenticatedRequest($request);
+ } catch (OAuthServerException $exception) {
+ return $exception->generateHttpResponse($response);
+ // @codeCoverageIgnoreStart
+ } catch (Exception $exception) {
+ return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500))
+ ->generateHttpResponse($response);
+ // @codeCoverageIgnoreEnd
+ }
+
+ // Pass the request and response on to the next responder in the chain
+ return $next($request, $response);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/RedirectUriValidators/RedirectUriValidator.php b/api_candidatos/vendor/league/oauth2-server/src/RedirectUriValidators/RedirectUriValidator.php
new file mode 100644
index 0000000..c758ad9
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/RedirectUriValidators/RedirectUriValidator.php
@@ -0,0 +1,120 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\RedirectUriValidators;
+
+use League\Uri\Exceptions\SyntaxError;
+use League\Uri\Uri;
+
+class RedirectUriValidator implements RedirectUriValidatorInterface
+{
+ /**
+ * @var array
+ */
+ private $allowedRedirectUris;
+
+ /**
+ * New validator instance for the given uri
+ *
+ * @param string|array $allowedRedirectUris
+ */
+ public function __construct($allowedRedirectUri)
+ {
+ if (\is_string($allowedRedirectUri)) {
+ $this->allowedRedirectUris = [$allowedRedirectUri];
+ } elseif (\is_array($allowedRedirectUri)) {
+ $this->allowedRedirectUris = $allowedRedirectUri;
+ } else {
+ $this->allowedRedirectUris = [];
+ }
+ }
+
+ /**
+ * Validates the redirect uri.
+ *
+ * @param string $redirectUri
+ *
+ * @return bool Return true if valid, false otherwise
+ */
+ public function validateRedirectUri($redirectUri)
+ {
+ if ($this->isLoopbackUri($redirectUri)) {
+ return $this->matchUriExcludingPort($redirectUri);
+ }
+
+ return $this->matchExactUri($redirectUri);
+ }
+
+ /**
+ * According to section 7.3 of rfc8252, loopback uris are:
+ * - "http://127.0.0.1:{port}/{path}" for IPv4
+ * - "http://[::1]:{port}/{path}" for IPv6
+ *
+ * @param string $redirectUri
+ *
+ * @return bool
+ */
+ private function isLoopbackUri($redirectUri)
+ {
+ try {
+ $uri = Uri::createFromString($redirectUri);
+ } catch (SyntaxError $e) {
+ return false;
+ }
+
+ return $uri->getScheme() === 'http'
+ && (\in_array($uri->getHost(), ['127.0.0.1', '[::1]'], true));
+ }
+
+ /**
+ * Find an exact match among allowed uris
+ *
+ * @param string $redirectUri
+ *
+ * @return bool Return true if an exact match is found, false otherwise
+ */
+ private function matchExactUri($redirectUri)
+ {
+ return \in_array($redirectUri, $this->allowedRedirectUris, true);
+ }
+
+ /**
+ * Find a match among allowed uris, allowing for different port numbers
+ *
+ * @param string $redirectUri
+ *
+ * @return bool Return true if a match is found, false otherwise
+ */
+ private function matchUriExcludingPort($redirectUri)
+ {
+ $parsedUrl = $this->parseUrlAndRemovePort($redirectUri);
+
+ foreach ($this->allowedRedirectUris as $allowedRedirectUri) {
+ if ($parsedUrl === $this->parseUrlAndRemovePort($allowedRedirectUri)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse an url like \parse_url, excluding the port
+ *
+ * @param string $url
+ *
+ * @return array
+ */
+ private function parseUrlAndRemovePort($url)
+ {
+ $uri = Uri::createFromString($url);
+
+ return (string) $uri->withPort(null);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/RedirectUriValidators/RedirectUriValidatorInterface.php b/api_candidatos/vendor/league/oauth2-server/src/RedirectUriValidators/RedirectUriValidatorInterface.php
new file mode 100644
index 0000000..d039085
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/RedirectUriValidators/RedirectUriValidatorInterface.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\RedirectUriValidators;
+
+interface RedirectUriValidatorInterface
+{
+ /**
+ * Validates the redirect uri.
+ *
+ * @param string $redirectUri
+ *
+ * @return bool Return true if valid, false otherwise
+ */
+ public function validateRedirectUri($redirectUri);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/AccessTokenRepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/AccessTokenRepositoryInterface.php
new file mode 100644
index 0000000..72ddf1f
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/AccessTokenRepositoryInterface.php
@@ -0,0 +1,57 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
+
+/**
+ * Access token interface.
+ */
+interface AccessTokenRepositoryInterface extends RepositoryInterface
+{
+ /**
+ * Create a new access token
+ *
+ * @param ClientEntityInterface $clientEntity
+ * @param ScopeEntityInterface[] $scopes
+ * @param mixed $userIdentifier
+ *
+ * @return AccessTokenEntityInterface
+ */
+ public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null);
+
+ /**
+ * Persists a new access token to permanent storage.
+ *
+ * @param AccessTokenEntityInterface $accessTokenEntity
+ *
+ * @throws UniqueTokenIdentifierConstraintViolationException
+ */
+ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity);
+
+ /**
+ * Revoke an access token.
+ *
+ * @param string $tokenId
+ */
+ public function revokeAccessToken($tokenId);
+
+ /**
+ * Check if the access token has been revoked.
+ *
+ * @param string $tokenId
+ *
+ * @return bool Return true if this token has been revoked
+ */
+ public function isAccessTokenRevoked($tokenId);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/AuthCodeRepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/AuthCodeRepositoryInterface.php
new file mode 100644
index 0000000..2dc285b
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/AuthCodeRepositoryInterface.php
@@ -0,0 +1,51 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
+use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
+
+/**
+ * Auth code storage interface.
+ */
+interface AuthCodeRepositoryInterface extends RepositoryInterface
+{
+ /**
+ * Creates a new AuthCode
+ *
+ * @return AuthCodeEntityInterface
+ */
+ public function getNewAuthCode();
+
+ /**
+ * Persists a new auth code to permanent storage.
+ *
+ * @param AuthCodeEntityInterface $authCodeEntity
+ *
+ * @throws UniqueTokenIdentifierConstraintViolationException
+ */
+ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity);
+
+ /**
+ * Revoke an auth code.
+ *
+ * @param string $codeId
+ */
+ public function revokeAuthCode($codeId);
+
+ /**
+ * Check if the auth code has been revoked.
+ *
+ * @param string $codeId
+ *
+ * @return bool Return true if this code has been revoked
+ */
+ public function isAuthCodeRevoked($codeId);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/ClientRepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/ClientRepositoryInterface.php
new file mode 100644
index 0000000..7eef494
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/ClientRepositoryInterface.php
@@ -0,0 +1,38 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+
+/**
+ * Client storage interface.
+ */
+interface ClientRepositoryInterface extends RepositoryInterface
+{
+ /**
+ * Get a client.
+ *
+ * @param string $clientIdentifier The client's identifier
+ *
+ * @return ClientEntityInterface|null
+ */
+ public function getClientEntity($clientIdentifier);
+
+ /**
+ * Validate a client's secret.
+ *
+ * @param string $clientIdentifier The client's identifier
+ * @param null|string $clientSecret The client's secret (if sent)
+ * @param null|string $grantType The type of grant the client is using (if sent)
+ *
+ * @return bool
+ */
+ public function validateClient($clientIdentifier, $clientSecret, $grantType);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/RefreshTokenRepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/RefreshTokenRepositoryInterface.php
new file mode 100644
index 0000000..a769cf6
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/RefreshTokenRepositoryInterface.php
@@ -0,0 +1,51 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
+use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
+
+/**
+ * Refresh token interface.
+ */
+interface RefreshTokenRepositoryInterface extends RepositoryInterface
+{
+ /**
+ * Creates a new refresh token
+ *
+ * @return RefreshTokenEntityInterface|null
+ */
+ public function getNewRefreshToken();
+
+ /**
+ * Create a new refresh token_name.
+ *
+ * @param RefreshTokenEntityInterface $refreshTokenEntity
+ *
+ * @throws UniqueTokenIdentifierConstraintViolationException
+ */
+ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity);
+
+ /**
+ * Revoke the refresh token.
+ *
+ * @param string $tokenId
+ */
+ public function revokeRefreshToken($tokenId);
+
+ /**
+ * Check if the refresh token has been revoked.
+ *
+ * @param string $tokenId
+ *
+ * @return bool Return true if this token has been revoked
+ */
+ public function isRefreshTokenRevoked($tokenId);
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/RepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/RepositoryInterface.php
new file mode 100644
index 0000000..9c27b4b
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/RepositoryInterface.php
@@ -0,0 +1,17 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+/**
+ * Repository interface.
+ */
+interface RepositoryInterface
+{
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/ScopeRepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/ScopeRepositoryInterface.php
new file mode 100644
index 0000000..997aac2
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/ScopeRepositoryInterface.php
@@ -0,0 +1,46 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+
+/**
+ * Scope interface.
+ */
+interface ScopeRepositoryInterface extends RepositoryInterface
+{
+ /**
+ * Return information about a scope.
+ *
+ * @param string $identifier The scope identifier
+ *
+ * @return ScopeEntityInterface|null
+ */
+ public function getScopeEntityByIdentifier($identifier);
+
+ /**
+ * Given a client, grant type and optional user identifier validate the set of scopes requested are valid and optionally
+ * append additional scopes or remove requested scopes.
+ *
+ * @param ScopeEntityInterface[] $scopes
+ * @param string $grantType
+ * @param ClientEntityInterface $clientEntity
+ * @param null|string $userIdentifier
+ *
+ * @return ScopeEntityInterface[]
+ */
+ public function finalizeScopes(
+ array $scopes,
+ $grantType,
+ ClientEntityInterface $clientEntity,
+ $userIdentifier = null
+ );
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/Repositories/UserRepositoryInterface.php b/api_candidatos/vendor/league/oauth2-server/src/Repositories/UserRepositoryInterface.php
new file mode 100644
index 0000000..8ad49aa
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/Repositories/UserRepositoryInterface.php
@@ -0,0 +1,33 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\Repositories;
+
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\UserEntityInterface;
+
+interface UserRepositoryInterface extends RepositoryInterface
+{
+ /**
+ * Get a user entity.
+ *
+ * @param string $username
+ * @param string $password
+ * @param string $grantType The grant type used
+ * @param ClientEntityInterface $clientEntity
+ *
+ * @return UserEntityInterface|null
+ */
+ public function getUserEntityByUserCredentials(
+ $username,
+ $password,
+ $grantType,
+ ClientEntityInterface $clientEntity
+ );
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/RequestAccessTokenEvent.php b/api_candidatos/vendor/league/oauth2-server/src/RequestAccessTokenEvent.php
new file mode 100644
index 0000000..c2f4782
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/RequestAccessTokenEvent.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class RequestAccessTokenEvent extends RequestEvent
+{
+ /**
+ * @var AccessTokenEntityInterface
+ */
+ private $accessToken;
+
+ /**
+ * @param string $name
+ * @param ServerRequestInterface $request
+ */
+ public function __construct($name, ServerRequestInterface $request, AccessTokenEntityInterface $accessToken)
+ {
+ parent::__construct($name, $request);
+ $this->accessToken = $accessToken;
+ }
+
+ /**
+ * @return AccessTokenEntityInterface
+ *
+ * @codeCoverageIgnore
+ */
+ public function getAccessToken()
+ {
+ return $this->accessToken;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/RequestEvent.php b/api_candidatos/vendor/league/oauth2-server/src/RequestEvent.php
new file mode 100644
index 0000000..4f7dad0
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/RequestEvent.php
@@ -0,0 +1,50 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use League\Event\Event;
+use Psr\Http\Message\ServerRequestInterface;
+
+class RequestEvent extends Event
+{
+ const CLIENT_AUTHENTICATION_FAILED = 'client.authentication.failed';
+ const USER_AUTHENTICATION_FAILED = 'user.authentication.failed';
+ const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed';
+
+ const REFRESH_TOKEN_ISSUED = 'refresh_token.issued';
+ const ACCESS_TOKEN_ISSUED = 'access_token.issued';
+
+ /**
+ * @var ServerRequestInterface
+ */
+ private $request;
+
+ /**
+ * RequestEvent constructor.
+ *
+ * @param string $name
+ * @param ServerRequestInterface $request
+ */
+ public function __construct($name, ServerRequestInterface $request)
+ {
+ parent::__construct($name);
+ $this->request = $request;
+ }
+
+ /**
+ * @return ServerRequestInterface
+ *
+ * @codeCoverageIgnore
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/RequestRefreshTokenEvent.php b/api_candidatos/vendor/league/oauth2-server/src/RequestRefreshTokenEvent.php
new file mode 100644
index 0000000..326a115
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/RequestRefreshTokenEvent.php
@@ -0,0 +1,41 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class RequestRefreshTokenEvent extends RequestEvent
+{
+ /**
+ * @var RefreshTokenEntityInterface
+ */
+ private $refreshToken;
+
+ /**
+ * @param string $name
+ * @param ServerRequestInterface $request
+ */
+ public function __construct($name, ServerRequestInterface $request, RefreshTokenEntityInterface $refreshToken)
+ {
+ parent::__construct($name, $request);
+ $this->refreshToken = $refreshToken;
+ }
+
+ /**
+ * @return RefreshTokenEntityInterface
+ *
+ * @codeCoverageIgnore
+ */
+ public function getRefreshToken()
+ {
+ return $this->refreshToken;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/RequestTypes/AuthorizationRequest.php b/api_candidatos/vendor/league/oauth2-server/src/RequestTypes/AuthorizationRequest.php
new file mode 100644
index 0000000..6441e14
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/RequestTypes/AuthorizationRequest.php
@@ -0,0 +1,224 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\RequestTypes;
+
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+use League\OAuth2\Server\Entities\UserEntityInterface;
+
+class AuthorizationRequest
+{
+ /**
+ * The grant type identifier
+ *
+ * @var string
+ */
+ protected $grantTypeId;
+
+ /**
+ * The client identifier
+ *
+ * @var ClientEntityInterface
+ */
+ protected $client;
+
+ /**
+ * The user identifier
+ *
+ * @var UserEntityInterface
+ */
+ protected $user;
+
+ /**
+ * An array of scope identifiers
+ *
+ * @var ScopeEntityInterface[]
+ */
+ protected $scopes = [];
+
+ /**
+ * Has the user authorized the authorization request
+ *
+ * @var bool
+ */
+ protected $authorizationApproved = false;
+
+ /**
+ * The redirect URI used in the request
+ *
+ * @var string|null
+ */
+ protected $redirectUri;
+
+ /**
+ * The state parameter on the authorization request
+ *
+ * @var string|null
+ */
+ protected $state;
+
+ /**
+ * The code challenge (if provided)
+ *
+ * @var string
+ */
+ protected $codeChallenge;
+
+ /**
+ * The code challenge method (if provided)
+ *
+ * @var string
+ */
+ protected $codeChallengeMethod;
+
+ /**
+ * @return string
+ */
+ public function getGrantTypeId()
+ {
+ return $this->grantTypeId;
+ }
+
+ /**
+ * @param string $grantTypeId
+ */
+ public function setGrantTypeId($grantTypeId)
+ {
+ $this->grantTypeId = $grantTypeId;
+ }
+
+ /**
+ * @return ClientEntityInterface
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ /**
+ * @param ClientEntityInterface $client
+ */
+ public function setClient(ClientEntityInterface $client)
+ {
+ $this->client = $client;
+ }
+
+ /**
+ * @return UserEntityInterface|null
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+ /**
+ * @param UserEntityInterface $user
+ */
+ public function setUser(UserEntityInterface $user)
+ {
+ $this->user = $user;
+ }
+
+ /**
+ * @return ScopeEntityInterface[]
+ */
+ public function getScopes()
+ {
+ return $this->scopes;
+ }
+
+ /**
+ * @param ScopeEntityInterface[] $scopes
+ */
+ public function setScopes(array $scopes)
+ {
+ $this->scopes = $scopes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isAuthorizationApproved()
+ {
+ return $this->authorizationApproved;
+ }
+
+ /**
+ * @param bool $authorizationApproved
+ */
+ public function setAuthorizationApproved($authorizationApproved)
+ {
+ $this->authorizationApproved = $authorizationApproved;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getRedirectUri()
+ {
+ return $this->redirectUri;
+ }
+
+ /**
+ * @param string|null $redirectUri
+ */
+ public function setRedirectUri($redirectUri)
+ {
+ $this->redirectUri = $redirectUri;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ /**
+ * @param string $state
+ */
+ public function setState($state)
+ {
+ $this->state = $state;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCodeChallenge()
+ {
+ return $this->codeChallenge;
+ }
+
+ /**
+ * @param string $codeChallenge
+ */
+ public function setCodeChallenge($codeChallenge)
+ {
+ $this->codeChallenge = $codeChallenge;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCodeChallengeMethod()
+ {
+ return $this->codeChallengeMethod;
+ }
+
+ /**
+ * @param string $codeChallengeMethod
+ */
+ public function setCodeChallengeMethod($codeChallengeMethod)
+ {
+ $this->codeChallengeMethod = $codeChallengeMethod;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/ResourceServer.php b/api_candidatos/vendor/league/oauth2-server/src/ResourceServer.php
new file mode 100644
index 0000000..d20d80d
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/ResourceServer.php
@@ -0,0 +1,86 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server;
+
+use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface;
+use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class ResourceServer
+{
+ /**
+ * @var AccessTokenRepositoryInterface
+ */
+ private $accessTokenRepository;
+
+ /**
+ * @var CryptKey
+ */
+ private $publicKey;
+
+ /**
+ * @var null|AuthorizationValidatorInterface
+ */
+ private $authorizationValidator;
+
+ /**
+ * New server instance.
+ *
+ * @param AccessTokenRepositoryInterface $accessTokenRepository
+ * @param CryptKey|string $publicKey
+ * @param null|AuthorizationValidatorInterface $authorizationValidator
+ */
+ public function __construct(
+ AccessTokenRepositoryInterface $accessTokenRepository,
+ $publicKey,
+ ?AuthorizationValidatorInterface $authorizationValidator = null
+ ) {
+ $this->accessTokenRepository = $accessTokenRepository;
+
+ if ($publicKey instanceof CryptKey === false) {
+ $publicKey = new CryptKey($publicKey);
+ }
+ $this->publicKey = $publicKey;
+
+ $this->authorizationValidator = $authorizationValidator;
+ }
+
+ /**
+ * @return AuthorizationValidatorInterface
+ */
+ protected function getAuthorizationValidator()
+ {
+ if ($this->authorizationValidator instanceof AuthorizationValidatorInterface === false) {
+ $this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
+ }
+
+ if ($this->authorizationValidator instanceof BearerTokenValidator === true) {
+ $this->authorizationValidator->setPublicKey($this->publicKey);
+ }
+
+ return $this->authorizationValidator;
+ }
+
+ /**
+ * Determine the access token validity.
+ *
+ * @param ServerRequestInterface $request
+ *
+ * @throws OAuthServerException
+ *
+ * @return ServerRequestInterface
+ */
+ public function validateAuthenticatedRequest(ServerRequestInterface $request)
+ {
+ return $this->getAuthorizationValidator()->validateAuthorization($request);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/AbstractResponseType.php b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/AbstractResponseType.php
new file mode 100644
index 0000000..192f52a
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/AbstractResponseType.php
@@ -0,0 +1,63 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\ResponseTypes;
+
+use League\OAuth2\Server\CryptKey;
+use League\OAuth2\Server\CryptTrait;
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
+
+abstract class AbstractResponseType implements ResponseTypeInterface
+{
+ use CryptTrait;
+
+ /**
+ * @var AccessTokenEntityInterface
+ */
+ protected $accessToken;
+
+ /**
+ * @var RefreshTokenEntityInterface
+ */
+ protected $refreshToken;
+
+ /**
+ * @var CryptKey
+ */
+ protected $privateKey;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAccessToken(AccessTokenEntityInterface $accessToken)
+ {
+ $this->accessToken = $accessToken;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken)
+ {
+ $this->refreshToken = $refreshToken;
+ }
+
+ /**
+ * Set the private key
+ *
+ * @param CryptKey $key
+ */
+ public function setPrivateKey(CryptKey $key)
+ {
+ $this->privateKey = $key;
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/BearerTokenResponse.php b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/BearerTokenResponse.php
new file mode 100644
index 0000000..afafcf3
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/BearerTokenResponse.php
@@ -0,0 +1,81 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\ResponseTypes;
+
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
+use LogicException;
+use Psr\Http\Message\ResponseInterface;
+
+class BearerTokenResponse extends AbstractResponseType
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function generateHttpResponse(ResponseInterface $response)
+ {
+ $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp();
+
+ $responseParams = [
+ 'token_type' => 'Bearer',
+ 'expires_in' => $expireDateTime - \time(),
+ 'access_token' => (string) $this->accessToken,
+ ];
+
+ if ($this->refreshToken instanceof RefreshTokenEntityInterface) {
+ $refreshTokenPayload = \json_encode([
+ 'client_id' => $this->accessToken->getClient()->getIdentifier(),
+ 'refresh_token_id' => $this->refreshToken->getIdentifier(),
+ 'access_token_id' => $this->accessToken->getIdentifier(),
+ 'scopes' => $this->accessToken->getScopes(),
+ 'user_id' => $this->accessToken->getUserIdentifier(),
+ 'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(),
+ ]);
+
+ if ($refreshTokenPayload === false) {
+ throw new LogicException('Error encountered JSON encoding the refresh token payload');
+ }
+
+ $responseParams['refresh_token'] = $this->encrypt($refreshTokenPayload);
+ }
+
+ $responseParams = \json_encode(\array_merge($this->getExtraParams($this->accessToken), $responseParams));
+
+ if ($responseParams === false) {
+ throw new LogicException('Error encountered JSON encoding response parameters');
+ }
+
+ $response = $response
+ ->withStatus(200)
+ ->withHeader('pragma', 'no-cache')
+ ->withHeader('cache-control', 'no-store')
+ ->withHeader('content-type', 'application/json; charset=UTF-8');
+
+ $response->getBody()->write($responseParams);
+
+ return $response;
+ }
+
+ /**
+ * Add custom fields to your Bearer Token response here, then override
+ * AuthorizationServer::getResponseType() to pull in your version of
+ * this class rather than the default.
+ *
+ * @param AccessTokenEntityInterface $accessToken
+ *
+ * @return array
+ */
+ protected function getExtraParams(AccessTokenEntityInterface $accessToken)
+ {
+ return [];
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/RedirectResponse.php b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/RedirectResponse.php
new file mode 100644
index 0000000..e463914
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/RedirectResponse.php
@@ -0,0 +1,40 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\ResponseTypes;
+
+use Psr\Http\Message\ResponseInterface;
+
+class RedirectResponse extends AbstractResponseType
+{
+ /**
+ * @var string
+ */
+ private $redirectUri;
+
+ /**
+ * @param string $redirectUri
+ */
+ public function setRedirectUri($redirectUri)
+ {
+ $this->redirectUri = $redirectUri;
+ }
+
+ /**
+ * @param ResponseInterface $response
+ *
+ * @return ResponseInterface
+ */
+ public function generateHttpResponse(ResponseInterface $response)
+ {
+ return $response->withStatus(302)->withHeader('Location', $this->redirectUri);
+ }
+}
diff --git a/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/ResponseTypeInterface.php b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/ResponseTypeInterface.php
new file mode 100644
index 0000000..5eddd60
--- /dev/null
+++ b/api_candidatos/vendor/league/oauth2-server/src/ResponseTypes/ResponseTypeInterface.php
@@ -0,0 +1,44 @@
+
+ * @copyright Copyright (c) Alex Bilbie
+ * @license http://mit-license.org/
+ *
+ * @link https://github.com/thephpleague/oauth2-server
+ */
+
+namespace League\OAuth2\Server\ResponseTypes;
+
+use Defuse\Crypto\Key;
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
+use Psr\Http\Message\ResponseInterface;
+
+interface ResponseTypeInterface
+{
+ /**
+ * @param AccessTokenEntityInterface $accessToken
+ */
+ public function setAccessToken(AccessTokenEntityInterface $accessToken);
+
+ /**
+ * @param RefreshTokenEntityInterface $refreshToken
+ */
+ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken);
+
+ /**
+ * @param ResponseInterface $response
+ *
+ * @return ResponseInterface
+ */
+ public function generateHttpResponse(ResponseInterface $response);
+
+ /**
+ * Set the encryption key
+ *
+ * @param string|Key|null $key
+ */
+ public function setEncryptionKey($key = null);
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/LICENSE b/api_candidatos/vendor/league/uri-interfaces/LICENSE
new file mode 100644
index 0000000..14c82cd
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 ignace nyamagana butera
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/api_candidatos/vendor/league/uri-interfaces/composer.json b/api_candidatos/vendor/league/uri-interfaces/composer.json
new file mode 100644
index 0000000..fc34cfe
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/composer.json
@@ -0,0 +1,68 @@
+{
+ "name": "league/uri-interfaces",
+ "description" : "Common interface for URI representation",
+ "keywords": [
+ "url",
+ "uri",
+ "rfc3986",
+ "rfc3987"
+ ],
+ "license": "MIT",
+ "homepage": "http://github.com/thephpleague/uri-interfaces",
+ "authors": [
+ {
+ "name" : "Ignace Nyamagana Butera",
+ "email" : "nyamsprod@gmail.com",
+ "homepage" : "https://nyamsprod.com"
+ }
+ ],
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nyamsprod"
+ }
+ ],
+ "require": {
+ "php" : "^7.2 || ^8.0",
+ "ext-json": "*"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "phpstan/phpstan": "^0.12.90",
+ "phpstan/phpstan-strict-rules": "^0.12.9",
+ "phpstan/phpstan-phpunit": "^0.12.19",
+ "phpunit/phpunit": "^8.5.15 || ^9.5"
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Uri\\": "src/"
+ }
+ },
+ "scripts": {
+ "phpunit": "phpunit --coverage-text",
+ "phpcs": "php-cs-fixer fix --dry-run --diff -vvv --allow-risky=yes --ansi",
+ "phpcs:fix": "php-cs-fixer fix -vvv --allow-risky=yes --ansi",
+ "phpstan": "phpstan analyse -l max -c phpstan.neon src --ansi --memory-limit 192M",
+ "test": [
+ "@phpunit",
+ "@phpstan",
+ "@phpcs:fix"
+ ]
+ },
+ "scripts-descriptions": {
+ "phpunit": "Runs package test suite",
+ "phpstan": "Runs complete codebase static analysis",
+ "phpcs": "Runs coding style testing",
+ "phpcs:fix": "Fix coding style issues",
+ "test": "Runs all tests"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "suggest": {
+ "ext-intl": "to use the IDNA feature",
+ "symfony/intl": "to use the IDNA feature via Symfony Polyfill"
+ }
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/AuthorityInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/AuthorityInterface.php
new file mode 100644
index 0000000..ed6c2b8
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/AuthorityInterface.php
@@ -0,0 +1,87 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use League\Uri\Exceptions\IdnSupportMissing;
+use League\Uri\Exceptions\SyntaxError;
+
+interface AuthorityInterface extends UriComponentInterface
+{
+ /**
+ * Returns the host component of the authority.
+ */
+ public function getHost(): ?string;
+
+ /**
+ * Returns the port component of the authority.
+ */
+ public function getPort(): ?int;
+
+ /**
+ * Returns the user information component of the authority.
+ */
+ public function getUserInfo(): ?string;
+
+ /**
+ * Return an instance with the specified host.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified host.
+ *
+ * A null value provided for the host is equivalent to removing the host
+ * information.
+ *
+ * @param ?string $host
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ * @throws IdnSupportMissing for component or transformations
+ * requiring IDN support when IDN support is not present
+ * or misconfigured.
+ */
+ public function withHost(?string $host): self;
+
+ /**
+ * Return an instance with the specified port.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified port.
+ *
+ * A null value provided for the port is equivalent to removing the port
+ * information.
+ *
+ * @param ?int $port
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withPort(?int $port): self;
+
+ /**
+ * Return an instance with the specified user information.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user information.
+ *
+ * Password is optional, but the user information MUST include the
+ * user; a null value for the user is equivalent to removing user
+ * information.
+ *
+ * @param ?string $user
+ * @param ?string $password
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withUserInfo(?string $user, ?string $password = null): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/DataPathInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/DataPathInterface.php
new file mode 100644
index 0000000..1e4f385
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/DataPathInterface.php
@@ -0,0 +1,92 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+interface DataPathInterface extends PathInterface
+{
+ /**
+ * Retrieve the data mime type associated to the URI.
+ *
+ * If no mimetype is present, this method MUST return the default mimetype 'text/plain'.
+ *
+ * @see http://tools.ietf.org/html/rfc2397#section-2
+ */
+ public function getMimeType(): string;
+
+ /**
+ * Retrieve the parameters associated with the Mime Type of the URI.
+ *
+ * If no parameters is present, this method MUST return the default parameter 'charset=US-ASCII'.
+ *
+ * @see http://tools.ietf.org/html/rfc2397#section-2
+ */
+ public function getParameters(): string;
+
+ /**
+ * Retrieve the mediatype associated with the URI.
+ *
+ * If no mediatype is present, this method MUST return the default parameter 'text/plain;charset=US-ASCII'.
+ *
+ * @see http://tools.ietf.org/html/rfc2397#section-3
+ *
+ * @return string The URI scheme.
+ */
+ public function getMediaType(): string;
+
+ /**
+ * Retrieves the data string.
+ *
+ * Retrieves the data part of the path. If no data part is provided return
+ * a empty string
+ */
+ public function getData(): string;
+
+ /**
+ * Tells whether the data is binary safe encoded.
+ */
+ public function isBinaryData(): bool;
+
+ /**
+ * Save the data to a specific file.
+ */
+ public function save(string $path, string $mode = 'w'): \SplFileObject;
+
+ /**
+ * Returns an instance where the data part is base64 encoded.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance where the data part is base64 encoded
+ */
+ public function toBinary(): self;
+
+ /**
+ * Returns an instance where the data part is url encoded following RFC3986 rules.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance where the data part is url encoded
+ */
+ public function toAscii(): self;
+
+ /**
+ * Return an instance with the specified mediatype parameters.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified mediatype parameters.
+ *
+ * Users must provide encoded characters.
+ *
+ * An empty parameters value is equivalent to removing the parameter.
+ */
+ public function withParameters(string $parameters): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/DomainHostInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/DomainHostInterface.php
new file mode 100644
index 0000000..2490310
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/DomainHostInterface.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use League\Uri\Exceptions\SyntaxError;
+
+/**
+ * @extends \IteratorAggregate
+ */
+interface DomainHostInterface extends \Countable, HostInterface, \IteratorAggregate
+{
+ /**
+ * Returns the labels total number.
+ */
+ public function count(): int;
+
+ /**
+ * Iterate over the Domain labels.
+ *
+ * @return \Iterator
+ */
+ public function getIterator(): \Iterator;
+
+ /**
+ * Retrieves a single host label.
+ *
+ * If the label offset has not been set, returns the null value.
+ */
+ public function get(int $offset): ?string;
+
+ /**
+ * Returns the associated key for a specific label or all the keys.
+ *
+ * @param ?string $label
+ *
+ * @return int[]
+ */
+ public function keys(?string $label = null): array;
+
+ /**
+ * Tells whether the domain is absolute.
+ */
+ public function isAbsolute(): bool;
+
+ /**
+ * Prepends a label to the host.
+ */
+ public function prepend(string $label): self;
+
+ /**
+ * Appends a label to the host.
+ */
+ public function append(string $label): self;
+
+ /**
+ * Returns an instance with its Root label.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ public function withRootLabel(): self;
+
+ /**
+ * Returns an instance without its Root label.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ public function withoutRootLabel(): self;
+
+ /**
+ * Returns an instance with the modified label.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the new label
+ *
+ * If $key is non-negative, the added label will be the label at $key position from the start.
+ * If $key is negative, the added label will be the label at $key position from the end.
+ *
+ * @throws SyntaxError If the key is invalid
+ */
+ public function withLabel(int $key, string $label): self;
+
+ /**
+ * Returns an instance without the specified label.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified component
+ *
+ * If $key is non-negative, the removed label will be the label at $key position from the start.
+ * If $key is negative, the removed label will be the label at $key position from the end.
+ *
+ * @param int ...$keys
+ *
+ * @throws SyntaxError If the key is invalid
+ */
+ public function withoutLabel(int ...$keys): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/FragmentInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/FragmentInterface.php
new file mode 100644
index 0000000..3d80f06
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/FragmentInterface.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+interface FragmentInterface extends UriComponentInterface
+{
+ /**
+ * Returns the decoded fragment.
+ */
+ public function decoded(): ?string;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/HostInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/HostInterface.php
new file mode 100644
index 0000000..a8b8bb3
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/HostInterface.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+interface HostInterface extends UriComponentInterface
+{
+ /**
+ * Returns the ascii representation.
+ */
+ public function toAscii(): ?string;
+
+ /**
+ * Returns the unicode representation.
+ */
+ public function toUnicode(): ?string;
+
+ /**
+ * Returns the IP version.
+ *
+ * If the host is a not an IP this method will return null
+ */
+ public function getIpVersion(): ?string;
+
+ /**
+ * Returns the IP component If the Host is an IP address.
+ *
+ * If the host is a not an IP this method will return null
+ */
+ public function getIp(): ?string;
+
+ /**
+ * Tells whether the host is a domain name.
+ */
+ public function isDomain(): bool;
+
+ /**
+ * Tells whether the host is an IP Address.
+ */
+ public function isIp(): bool;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/IpHostInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/IpHostInterface.php
new file mode 100644
index 0000000..1e2242a
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/IpHostInterface.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+interface IpHostInterface extends HostInterface
+{
+ /**
+ * Returns whether or not the host is an IPv4 address.
+ */
+ public function isIpv4(): bool;
+ /**
+ * Returns whether or not the host is an IPv6 address.
+ */
+ public function isIpv6(): bool;
+
+ /**
+ * Returns whether or not the host is an IPv6 address.
+ */
+ public function isIpFuture(): bool;
+
+ /**
+ * Returns whether or not the host has a ZoneIdentifier.
+ *
+ * @see http://tools.ietf.org/html/rfc6874#section-4
+ */
+ public function hasZoneIdentifier(): bool;
+
+ /**
+ * Returns an host without its zone identifier according to RFC6874.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance without the host zone identifier according to RFC6874
+ *
+ * @see http://tools.ietf.org/html/rfc6874#section-4
+ */
+ public function withoutZoneIdentifier(): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/PathInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/PathInterface.php
new file mode 100644
index 0000000..389c0ff
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/PathInterface.php
@@ -0,0 +1,90 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use League\Uri\Exceptions\SyntaxError;
+
+interface PathInterface extends UriComponentInterface
+{
+ /**
+ * Returns the decoded path.
+ */
+ public function decoded(): string;
+
+ /**
+ * Returns whether or not the path is absolute or relative.
+ */
+ public function isAbsolute(): bool;
+
+ /**
+ * Returns whether or not the path has a trailing delimiter.
+ */
+ public function hasTrailingSlash(): bool;
+
+ /**
+ * Returns an instance without dot segments.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the path component normalized by removing
+ * the dot segment.
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withoutDotSegments(): self;
+
+ /**
+ * Returns an instance with a leading slash.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the path component with a leading slash
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withLeadingSlash(): self;
+
+ /**
+ * Returns an instance without a leading slash.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the path component without a leading slash
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withoutLeadingSlash(): self;
+
+ /**
+ * Returns an instance with a trailing slash.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the path component with a trailing slash
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withTrailingSlash(): self;
+
+ /**
+ * Returns an instance without a trailing slash.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the path component without a trailing slash
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withoutTrailingSlash(): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/PortInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/PortInterface.php
new file mode 100644
index 0000000..7230c4a
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/PortInterface.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+interface PortInterface extends UriComponentInterface
+{
+ /**
+ * Returns the integer representation of the Port.
+ */
+ public function toInt(): ?int;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/QueryInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/QueryInterface.php
new file mode 100644
index 0000000..f7081ea
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/QueryInterface.php
@@ -0,0 +1,227 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+/**
+ * @extends \IteratorAggregate
+ */
+interface QueryInterface extends \Countable, \IteratorAggregate, UriComponentInterface
+{
+ /**
+ * Returns the query separator.
+ */
+ public function getSeparator(): string;
+
+ /**
+ * Returns the number of key/value pairs present in the object.
+ */
+ public function count(): int;
+
+ /**
+ * Returns an iterator allowing to go through all key/value pairs contained in this object.
+ *
+ * The pair is represented as an array where the first value is the pair key
+ * and the second value the pair value.
+ *
+ * The key of each pair is a string
+ * The value of each pair is a scalar or the null value
+ *
+ * @return \Iterator
+ */
+ public function getIterator(): \Iterator;
+
+ /**
+ * Returns an iterator allowing to go through all key/value pairs contained in this object.
+ *
+ * The return type is as a Iterator where its offset is the pair key and its value the pair value.
+ *
+ * The key of each pair is a string
+ * The value of each pair is a scalar or the null value
+ *
+ * @return iterable
+ */
+ public function pairs(): iterable;
+
+ /**
+ * Tells whether a pair with a specific name exists.
+ *
+ * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has
+ */
+ public function has(string $key): bool;
+
+ /**
+ * Returns the first value associated to the given pair name.
+ *
+ * If no value is found null is returned
+ *
+ * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get
+ */
+ public function get(string $key): ?string;
+
+ /**
+ * Returns all the values associated to the given pair name as an array or all
+ * the instance pairs.
+ *
+ * If no value is found an empty array is returned
+ *
+ * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall
+ *
+ * @return array
+ */
+ public function getAll(string $key): array;
+
+ /**
+ * Returns the store PHP variables as elements of an array.
+ *
+ * The result is similar as PHP parse_str when used with its
+ * second argument with the difference that variable names are
+ * not mangled.
+ *
+ * If a key is submitted it will returns the value attached to it or null
+ *
+ * @see http://php.net/parse_str
+ * @see https://wiki.php.net/rfc/on_demand_name_mangling
+ *
+ * @param ?string $key
+ * @return mixed the collection of stored PHP variables or the empty array if no input is given,
+ * the single value of a stored PHP variable or null if the variable is not present in the collection
+ */
+ public function params(?string $key = null);
+
+ /**
+ * Returns the RFC1738 encoded query.
+ */
+ public function toRFC1738(): ?string;
+
+ /**
+ * Returns the RFC3986 encoded query.
+ *
+ * @see ::getContent
+ */
+ public function toRFC3986(): ?string;
+
+ /**
+ * Returns an instance with a different separator.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the query component with a different separator
+ */
+ public function withSeparator(string $separator): self;
+
+ /**
+ * Sorts the query string by offset, maintaining offset to data correlations.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified query
+ *
+ * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort
+ */
+ public function sort(): self;
+
+ /**
+ * Returns an instance without duplicate key/value pair.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the query component normalized by removing
+ * duplicate pairs whose key/value are the same.
+ */
+ public function withoutDuplicates(): self;
+
+ /**
+ * Returns an instance without empty key/value where the value is the null value.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the query component normalized by removing
+ * empty pairs.
+ *
+ * A pair is considered empty if its value is equal to the null value
+ */
+ public function withoutEmptyPairs(): self;
+
+ /**
+ * Returns an instance where numeric indices associated to PHP's array like key are removed.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the query component normalized so that numeric indexes
+ * are removed from the pair key value.
+ *
+ * ie.: toto[3]=bar[3]&foo=bar becomes toto[]=bar[3]&foo=bar
+ */
+ public function withoutNumericIndices(): self;
+
+ /**
+ * Returns an instance with the a new key/value pair added to it.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified query
+ *
+ * If the pair already exists the value will replace the existing value.
+ *
+ * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set
+ *
+ * @param ?string $value
+ */
+ public function withPair(string $key, ?string $value): self;
+
+ /**
+ * Returns an instance with the new pairs set to it.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified query
+ *
+ * @see ::withPair
+ */
+ public function merge(string $query): self;
+
+ /**
+ * Returns an instance without the specified keys.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified component
+ *
+ * @param string ...$keys
+ */
+ public function withoutPair(string ...$keys): self;
+
+ /**
+ * Returns a new instance with a specified key/value pair appended as a new pair.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified query
+ *
+ * @param ?string $value
+ */
+ public function appendTo(string $key, ?string $value): self;
+
+ /**
+ * Returns an instance with the new pairs appended to it.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified query
+ *
+ * If the pair already exists the value will be added to it.
+ */
+ public function append(string $query): self;
+
+ /**
+ * Returns an instance without the specified params.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified component without PHP's value.
+ * PHP's mangled is not taken into account.
+ *
+ * @param string ...$keys
+ */
+ public function withoutParam(string ...$keys): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/SegmentedPathInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/SegmentedPathInterface.php
new file mode 100644
index 0000000..53065ff
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/SegmentedPathInterface.php
@@ -0,0 +1,147 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use League\Uri\Exceptions\SyntaxError;
+
+/**
+ * @extends \IteratorAggregate
+ */
+interface SegmentedPathInterface extends \Countable, \IteratorAggregate, PathInterface
+{
+ /**
+ * Returns the total number of segments in the path.
+ */
+ public function count(): int;
+
+ /**
+ * Iterate over the path segment.
+ *
+ * @return \Iterator
+ */
+ public function getIterator(): \Iterator;
+
+ /**
+ * Returns parent directory's path.
+ */
+ public function getDirname(): string;
+
+ /**
+ * Returns the path basename.
+ */
+ public function getBasename(): string;
+
+ /**
+ * Returns the basename extension.
+ */
+ public function getExtension(): string;
+
+ /**
+ * Retrieves a single path segment.
+ *
+ * If the segment offset has not been set, returns null.
+ */
+ public function get(int $offset): ?string;
+
+ /**
+ * Returns the associated key for a specific segment.
+ *
+ * If a value is specified only the keys associated with
+ * the given value will be returned
+ *
+ * @param ?string $segment
+ *
+ * @return int[]
+ */
+ public function keys(?string $segment = null): array;
+
+ /**
+ * Appends a segment to the path.
+ */
+ public function append(string $segment): self;
+
+ /**
+ * Prepends a segment to the path.
+ */
+ public function prepend(string $segment): self;
+
+ /**
+ * Returns an instance with the modified segment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the new segment
+ *
+ * If $key is non-negative, the added segment will be the segment at $key position from the start.
+ * If $key is negative, the added segment will be the segment at $key position from the end.
+ *
+ * @param ?string $segment
+ *
+ * @throws SyntaxError If the key is invalid
+ */
+ public function withSegment(int $key, ?string $segment): self;
+
+ /**
+ * Returns an instance without the specified segment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified component
+ *
+ * If $key is non-negative, the removed segment will be the segment at $key position from the start.
+ * If $key is negative, the removed segment will be the segment at $key position from the end.
+ *
+ * @param int ...$keys remaining keys to remove
+ *
+ * @throws SyntaxError If the key is invalid
+ */
+ public function withoutSegment(int ...$keys): self;
+
+ /**
+ * Returns an instance without duplicate delimiters.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the path component normalized by removing
+ * multiple consecutive empty segment
+ */
+ public function withoutEmptySegments(): self;
+
+ /**
+ * Returns an instance with the specified parent directory's path.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the extension basename modified.
+ *
+ * @param ?string $path
+ */
+ public function withDirname(?string $path): self;
+
+ /**
+ * Returns an instance with the specified basename.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the extension basename modified.
+ *
+ * @param ?string $basename
+ */
+ public function withBasename(?string $basename): self;
+
+ /**
+ * Returns an instance with the specified basename extension.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the extension basename modified.
+ *
+ * @param ?string $extension
+ */
+ public function withExtension(?string $extension): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriComponentInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriComponentInterface.php
new file mode 100644
index 0000000..c7b39bb
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriComponentInterface.php
@@ -0,0 +1,88 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use League\Uri\Exceptions\IdnSupportMissing;
+use League\Uri\Exceptions\SyntaxError;
+
+interface UriComponentInterface extends \JsonSerializable
+{
+ /**
+ * Returns the instance content.
+ *
+ * If the instance is defined, the value returned MUST be encoded according to the
+ * selected encoding algorithm. In any case, the value MUST NOT double-encode any character
+ * depending on the selected encoding algorithm.
+ *
+ * To determine what characters to encode, please refer to RFC 3986, Sections 2 and 3.
+ * or RFC 3987 Section 3. By default the content is encoded according to RFC3986
+ *
+ * If the instance is not defined null is returned
+ */
+ public function getContent(): ?string;
+
+ /**
+ * Returns the instance string representation.
+ *
+ * If the instance is defined, the value returned MUST be percent-encoded,
+ * but MUST NOT double-encode any characters. To determine what characters
+ * to encode, please refer to RFC 3986, Sections 2 and 3.
+ *
+ * If the instance is not defined an empty string is returned
+ */
+ public function __toString(): string;
+
+ /**
+ * Returns the instance json representation.
+ *
+ * If the instance is defined, the value returned MUST be percent-encoded,
+ * but MUST NOT double-encode any characters. To determine what characters
+ * to encode, please refer to RFC 3986 or RFC 1738.
+ *
+ * If the instance is not defined null is returned
+ */
+ public function jsonSerialize(): ?string;
+
+ /**
+ * Returns the instance string representation with its optional URI delimiters.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode any
+ * characters. To determine what characters to encode, please refer to RFC 3986,
+ * Sections 2 and 3.
+ *
+ * If the instance is not defined an empty string is returned
+ */
+ public function getUriComponent(): string;
+
+ /**
+ * Returns an instance with the specified content.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified content.
+ *
+ * Users can provide both encoded and decoded content characters.
+ *
+ * A null value is equivalent to removing the component content.
+ *
+ *
+ * @param ?string $content
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ * @throws IdnSupportMissing for component or transformations
+ * requiring IDN support when IDN support is not present
+ * or misconfigured.
+ */
+ public function withContent(?string $content): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriException.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriException.php
new file mode 100644
index 0000000..c0fec2a
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriException.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use Throwable;
+
+interface UriException extends Throwable
+{
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriInterface.php
new file mode 100644
index 0000000..b6eb6a1
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UriInterface.php
@@ -0,0 +1,292 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+use League\Uri\Exceptions\IdnSupportMissing;
+use League\Uri\Exceptions\SyntaxError;
+
+interface UriInterface extends \JsonSerializable
+{
+ /**
+ * Returns the string representation as a URI reference.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
+ */
+ public function __toString(): string;
+
+ /**
+ * Returns the string representation as a URI reference.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
+ * @see ::__toString
+ */
+ public function jsonSerialize(): string;
+
+ /**
+ * Retrieve the scheme component of the URI.
+ *
+ * If no scheme is present, this method MUST return a null value.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.1.
+ *
+ * The trailing ":" character is not part of the scheme and MUST NOT be
+ * added.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.1
+ */
+ public function getScheme(): ?string;
+
+ /**
+ * Retrieve the authority component of the URI.
+ *
+ * If no scheme is present, this method MUST return a null value.
+ *
+ * If the port component is not set or is the standard port for the current
+ * scheme, it SHOULD NOT be included.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2
+ */
+ public function getAuthority(): ?string;
+
+ /**
+ * Retrieve the user information component of the URI.
+ *
+ * If no scheme is present, this method MUST return a null value.
+ *
+ * If a user is present in the URI, this will return that value;
+ * additionally, if the password is also present, it will be appended to the
+ * user value, with a colon (":") separating the values.
+ *
+ * The trailing "@" character is not part of the user information and MUST
+ * NOT be added.
+ */
+ public function getUserInfo(): ?string;
+
+ /**
+ * Retrieve the host component of the URI.
+ *
+ * If no host is present this method MUST return a null value.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.2.2.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ public function getHost(): ?string;
+
+ /**
+ * Retrieve the port component of the URI.
+ *
+ * If a port is present, and it is non-standard for the current scheme,
+ * this method MUST return it as an integer. If the port is the standard port
+ * used with the current scheme, this method SHOULD return null.
+ *
+ * If no port is present, and no scheme is present, this method MUST return
+ * a null value.
+ *
+ * If no port is present, but a scheme is present, this method MAY return
+ * the standard port for that scheme, but SHOULD return null.
+ */
+ public function getPort(): ?int;
+
+ /**
+ * Retrieve the path component of the URI.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * Normally, the empty path "" and absolute path "/" are considered equal as
+ * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
+ * do this normalization because in contexts with a trimmed base path, e.g.
+ * the front controller, this difference becomes significant. It's the task
+ * of the user to handle both "" and "/".
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.3.
+ *
+ * As an example, if the value should include a slash ("/") not intended as
+ * delimiter between path segments, that value MUST be passed in encoded
+ * form (e.g., "%2F") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.3
+ */
+ public function getPath(): string;
+
+ /**
+ * Retrieve the query string of the URI.
+ *
+ * If no host is present this method MUST return a null value.
+ *
+ * The leading "?" character is not part of the query and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.4.
+ *
+ * As an example, if a value in a key/value pair of the query string should
+ * include an ampersand ("&") not intended as a delimiter between values,
+ * that value MUST be passed in encoded form (e.g., "%26") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.4
+ */
+ public function getQuery(): ?string;
+
+ /**
+ * Retrieve the fragment component of the URI.
+ *
+ * If no host is present this method MUST return a null value.
+ *
+ * The leading "#" character is not part of the fragment and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.5.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.5
+ */
+ public function getFragment(): ?string;
+
+ /**
+ * Return an instance with the specified scheme.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified scheme.
+ *
+ * A null value provided for the scheme is equivalent to removing the scheme
+ * information.
+ *
+ * @param ?string $scheme
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withScheme(?string $scheme): self;
+
+ /**
+ * Return an instance with the specified user information.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user information.
+ *
+ * Password is optional, but the user information MUST include the
+ * user; a null value for the user is equivalent to removing user
+ * information.
+ *
+ * @param ?string $user
+ * @param ?string $password
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withUserInfo(?string $user, ?string $password = null): self;
+
+ /**
+ * Return an instance with the specified host.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified host.
+ *
+ * A null value provided for the host is equivalent to removing the host
+ * information.
+ *
+ * @param ?string $host
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ * @throws IdnSupportMissing for component or transformations
+ * requiring IDN support when IDN support is not present
+ * or misconfigured.
+ */
+ public function withHost(?string $host): self;
+
+ /**
+ * Return an instance with the specified port.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified port.
+ *
+ * A null value provided for the port is equivalent to removing the port
+ * information.
+ *
+ * @param ?int $port
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withPort(?int $port): self;
+
+ /**
+ * Return an instance with the specified path.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified path.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * Users can provide both encoded and decoded path characters.
+ * Implementations ensure the correct encoding as outlined in getPath().
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withPath(string $path): self;
+
+ /**
+ * Return an instance with the specified query string.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified query string.
+ *
+ * Users can provide both encoded and decoded query characters.
+ * Implementations ensure the correct encoding as outlined in getQuery().
+ *
+ * A null value provided for the query is equivalent to removing the query
+ * information.
+ *
+ * @param ?string $query
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withQuery(?string $query): self;
+
+ /**
+ * Return an instance with the specified URI fragment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified URI fragment.
+ *
+ * Users can provide both encoded and decoded fragment characters.
+ * Implementations ensure the correct encoding as outlined in getFragment().
+ *
+ * A null value provided for the fragment is equivalent to removing the fragment
+ * information.
+ *
+ * @param ?string $fragment
+ *
+ * @throws SyntaxError for invalid component or transformations
+ * that would result in a object in invalid state.
+ */
+ public function withFragment(?string $fragment): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UserInfoInterface.php b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UserInfoInterface.php
new file mode 100644
index 0000000..6411f9b
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Contracts/UserInfoInterface.php
@@ -0,0 +1,40 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Contracts;
+
+interface UserInfoInterface extends UriComponentInterface
+{
+ /**
+ * Returns the user component part.
+ */
+ public function getUser(): ?string;
+
+ /**
+ * Returns the pass component part.
+ */
+ public function getPass(): ?string;
+
+ /**
+ * Returns an instance with the specified user and/or pass.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user.
+ *
+ * An empty user is equivalent to removing the user information.
+ *
+ * @param ?string $user
+ * @param ?string $pass
+ */
+ public function withUserInfo(?string $user, ?string $pass = null): self;
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/FileinfoSupportMissing.php b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/FileinfoSupportMissing.php
new file mode 100644
index 0000000..0105b2d
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/FileinfoSupportMissing.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Exceptions;
+
+use League\Uri\Contracts\UriException;
+
+class FileinfoSupportMissing extends \RuntimeException implements UriException
+{
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/IdnSupportMissing.php b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/IdnSupportMissing.php
new file mode 100644
index 0000000..8ff3b53
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/IdnSupportMissing.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Exceptions;
+
+use League\Uri\Contracts\UriException;
+
+class IdnSupportMissing extends \RuntimeException implements UriException
+{
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/IdnaConversionFailed.php b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/IdnaConversionFailed.php
new file mode 100644
index 0000000..80259f3
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/IdnaConversionFailed.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Exceptions;
+
+use League\Uri\Idna\IdnaInfo;
+
+final class IdnaConversionFailed extends SyntaxError
+{
+ /** @var IdnaInfo|null */
+ private $idnaInfo;
+
+ private function __construct(string $message, IdnaInfo $idnaInfo = null)
+ {
+ parent::__construct($message);
+ $this->idnaInfo = $idnaInfo;
+ }
+
+ public static function dueToIDNAError(string $domain, IdnaInfo $idnaInfo): self
+ {
+ return new self(
+ 'The host `'.$domain.'` is invalid : '.implode(', ', $idnaInfo->errorList()).' .',
+ $idnaInfo
+ );
+ }
+
+ public static function dueToInvalidHost(string $domain): self
+ {
+ return new self('The host `'.$domain.'` is not a valid IDN host');
+ }
+
+ public function idnaInfo(): ?IdnaInfo
+ {
+ return $this->idnaInfo;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/SyntaxError.php b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/SyntaxError.php
new file mode 100644
index 0000000..1b5e4cb
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Exceptions/SyntaxError.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Exceptions;
+
+use League\Uri\Contracts\UriException;
+
+class SyntaxError extends \InvalidArgumentException implements UriException
+{
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Idna/Idna.php b/api_candidatos/vendor/league/uri-interfaces/src/Idna/Idna.php
new file mode 100644
index 0000000..5930687
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Idna/Idna.php
@@ -0,0 +1,212 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Idna;
+
+use League\Uri\Exceptions\IdnaConversionFailed;
+use League\Uri\Exceptions\IdnSupportMissing;
+use League\Uri\Exceptions\SyntaxError;
+use function defined;
+use function function_exists;
+use function idn_to_ascii;
+use function idn_to_utf8;
+use function rawurldecode;
+use const INTL_IDNA_VARIANT_UTS46;
+
+/**
+ * @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uidna_8h.html
+ */
+final class Idna
+{
+ private const REGEXP_IDNA_PATTERN = '/[^\x20-\x7f]/';
+ private const MAX_DOMAIN_LENGTH = 253;
+ private const MAX_LABEL_LENGTH = 63;
+
+ /**
+ * General registered name regular expression.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2.2
+ * @see https://regex101.com/r/fptU8V/1
+ */
+ private const REGEXP_REGISTERED_NAME = '/
+ (?(DEFINE)
+ (?[a-z0-9_~\-]) # . is missing as it is used to separate labels
+ (?[!$&\'()*+,;=])
+ (?%[A-F0-9]{2})
+ (?(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*)
+ )
+ ^(?:(?®_name)\.)*(?®_name)\.?$
+ /ix';
+
+ /**
+ * IDNA options.
+ */
+ public const IDNA_DEFAULT = 0;
+ public const IDNA_ALLOW_UNASSIGNED = 1;
+ public const IDNA_USE_STD3_RULES = 2;
+ public const IDNA_CHECK_BIDI = 4;
+ public const IDNA_CHECK_CONTEXTJ = 8;
+ public const IDNA_NONTRANSITIONAL_TO_ASCII = 0x10;
+ public const IDNA_NONTRANSITIONAL_TO_UNICODE = 0x20;
+ public const IDNA_CHECK_CONTEXTO = 0x40;
+
+ /**
+ * IDNA errors.
+ */
+ public const ERROR_NONE = 0;
+ public const ERROR_EMPTY_LABEL = 1;
+ public const ERROR_LABEL_TOO_LONG = 2;
+ public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
+ public const ERROR_LEADING_HYPHEN = 8;
+ public const ERROR_TRAILING_HYPHEN = 0x10;
+ public const ERROR_HYPHEN_3_4 = 0x20;
+ public const ERROR_LEADING_COMBINING_MARK = 0x40;
+ public const ERROR_DISALLOWED = 0x80;
+ public const ERROR_PUNYCODE = 0x100;
+ public const ERROR_LABEL_HAS_DOT = 0x200;
+ public const ERROR_INVALID_ACE_LABEL = 0x400;
+ public const ERROR_BIDI = 0x800;
+ public const ERROR_CONTEXTJ = 0x1000;
+ public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
+ public const ERROR_CONTEXTO_DIGITS = 0x4000;
+
+ /**
+ * IDNA default options.
+ */
+ public const IDNA2008_ASCII = self::IDNA_NONTRANSITIONAL_TO_ASCII
+ | self::IDNA_CHECK_BIDI
+ | self::IDNA_USE_STD3_RULES
+ | self::IDNA_CHECK_CONTEXTJ;
+ public const IDNA2008_UNICODE = self::IDNA_NONTRANSITIONAL_TO_UNICODE
+ | self::IDNA_CHECK_BIDI
+ | self::IDNA_USE_STD3_RULES
+ | self::IDNA_CHECK_CONTEXTJ;
+
+ /**
+ * @codeCoverageIgnore
+ */
+ private static function supportsIdna(): void
+ {
+ static $idnSupport;
+ if (null === $idnSupport) {
+ $idnSupport = function_exists('\idn_to_ascii') && defined('\INTL_IDNA_VARIANT_UTS46');
+ }
+
+ if (!$idnSupport) {
+ throw new IdnSupportMissing('IDN host can not be processed. Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6.');
+ }
+ }
+
+ /**
+ * Converts the input to its IDNA ASCII form.
+ *
+ * This method returns the string converted to IDN ASCII form
+ *
+ * @throws SyntaxError if the string can not be converted to ASCII using IDN UTS46 algorithm
+ */
+ public static function toAscii(string $domain, int $options): IdnaInfo
+ {
+ $domain = rawurldecode($domain);
+
+ if (1 === preg_match(self::REGEXP_IDNA_PATTERN, $domain)) {
+ self::supportsIdna();
+
+ /* @param-out array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
+ idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $idnaInfo);
+ if ([] === $idnaInfo) {
+ return IdnaInfo::fromIntl([
+ 'result' => strtolower($domain),
+ 'isTransitionalDifferent' => false,
+ 'errors' => self::validateDomainAndLabelLength($domain),
+ ]);
+ }
+
+ /* @var array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
+ return IdnaInfo::fromIntl($idnaInfo);
+ }
+
+ $error = self::ERROR_NONE;
+ if (1 !== preg_match(self::REGEXP_REGISTERED_NAME, $domain)) {
+ $error |= self::ERROR_DISALLOWED;
+ }
+
+ return IdnaInfo::fromIntl([
+ 'result' => strtolower($domain),
+ 'isTransitionalDifferent' => false,
+ 'errors' => self::validateDomainAndLabelLength($domain) | $error,
+ ]);
+ }
+
+ /**
+ * Converts the input to its IDNA UNICODE form.
+ *
+ * This method returns the string converted to IDN UNICODE form
+ *
+ * @throws SyntaxError if the string can not be converted to UNICODE using IDN UTS46 algorithm
+ */
+ public static function toUnicode(string $domain, int $options): IdnaInfo
+ {
+ $domain = rawurldecode($domain);
+
+ if (false === stripos($domain, 'xn--')) {
+ return IdnaInfo::fromIntl(['result' => $domain, 'isTransitionalDifferent' => false, 'errors' => self::ERROR_NONE]);
+ }
+
+ self::supportsIdna();
+
+ /* @param-out array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
+ idn_to_utf8($domain, $options, INTL_IDNA_VARIANT_UTS46, $idnaInfo);
+ if ([] === $idnaInfo) {
+ throw IdnaConversionFailed::dueToInvalidHost($domain);
+ }
+
+ /* @var array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
+ return IdnaInfo::fromIntl($idnaInfo);
+ }
+
+ /**
+ * Adapted from https://github.com/TRowbotham/idna.
+ *
+ * @see https://github.com/TRowbotham/idna/blob/master/src/Idna.php#L236
+ */
+ private static function validateDomainAndLabelLength(string $domain): int
+ {
+ $error = self::ERROR_NONE;
+ $labels = explode('.', $domain);
+ $maxDomainSize = self::MAX_DOMAIN_LENGTH;
+ $length = count($labels);
+
+ // If the last label is empty and it is not the first label, then it is the root label.
+ // Increase the max size by 1, making it 254, to account for the root label's "."
+ // delimiter. This also means we don't need to check the last label's length for being too
+ // long.
+ if ($length > 1 && $labels[$length - 1] === '') {
+ ++$maxDomainSize;
+ array_pop($labels);
+ }
+
+ if (strlen($domain) > $maxDomainSize) {
+ $error |= self::ERROR_DOMAIN_NAME_TOO_LONG;
+ }
+
+ foreach ($labels as $label) {
+ if (strlen($label) > self::MAX_LABEL_LENGTH) {
+ $error |= self::ERROR_LABEL_TOO_LONG;
+
+ break;
+ }
+ }
+
+ return $error;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri-interfaces/src/Idna/IdnaInfo.php b/api_candidatos/vendor/league/uri-interfaces/src/Idna/IdnaInfo.php
new file mode 100644
index 0000000..73610a2
--- /dev/null
+++ b/api_candidatos/vendor/league/uri-interfaces/src/Idna/IdnaInfo.php
@@ -0,0 +1,113 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Idna;
+
+use function array_filter;
+use const ARRAY_FILTER_USE_KEY;
+
+/**
+ * @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uidna_8h.html
+ */
+final class IdnaInfo
+{
+ private const ERRORS = [
+ Idna::ERROR_EMPTY_LABEL => 'a non-final domain name label (or the whole domain name) is empty',
+ Idna::ERROR_LABEL_TOO_LONG => 'a domain name label is longer than 63 bytes',
+ Idna::ERROR_DOMAIN_NAME_TOO_LONG => 'a domain name is longer than 255 bytes in its storage form',
+ Idna::ERROR_LEADING_HYPHEN => 'a label starts with a hyphen-minus ("-")',
+ Idna::ERROR_TRAILING_HYPHEN => 'a label ends with a hyphen-minus ("-")',
+ Idna::ERROR_HYPHEN_3_4 => 'a label contains hyphen-minus ("-") in the third and fourth positions',
+ Idna::ERROR_LEADING_COMBINING_MARK => 'a label starts with a combining mark',
+ Idna::ERROR_DISALLOWED => 'a label or domain name contains disallowed characters',
+ Idna::ERROR_PUNYCODE => 'a label starts with "xn--" but does not contain valid Punycode',
+ Idna::ERROR_LABEL_HAS_DOT => 'a label contains a dot=full stop',
+ Idna::ERROR_INVALID_ACE_LABEL => 'An ACE label does not contain a valid label string',
+ Idna::ERROR_BIDI => 'a label does not meet the IDNA BiDi requirements (for right-to-left characters)',
+ Idna::ERROR_CONTEXTJ => 'a label does not meet the IDNA CONTEXTJ requirements',
+ Idna::ERROR_CONTEXTO_DIGITS => 'a label does not meet the IDNA CONTEXTO requirements for digits',
+ Idna::ERROR_CONTEXTO_PUNCTUATION => 'a label does not meet the IDNA CONTEXTO requirements for punctuation characters. Some punctuation characters "Would otherwise have been DISALLOWED" but are allowed in certain contexts',
+ ];
+
+ /** @var string */
+ private $result;
+
+ /** @var bool */
+ private $isTransitionalDifferent;
+
+ /** @var int */
+ private $errors;
+
+ /**
+ * @var array
+ */
+ private $errorList;
+
+ private function __construct(string $result, bool $isTransitionalDifferent, int $errors)
+ {
+ $this->result = $result;
+ $this->errors = $errors;
+ $this->isTransitionalDifferent = $isTransitionalDifferent;
+ $this->errorList = array_filter(
+ self::ERRORS,
+ function (int $error): bool {
+ return 0 !== ($error & $this->errors);
+ },
+ ARRAY_FILTER_USE_KEY
+ );
+ }
+
+ /**
+ * @param array{result:string, isTransitionalDifferent:bool, errors:int} $infos
+ */
+ public static function fromIntl(array $infos): self
+ {
+ return new self($infos['result'], $infos['isTransitionalDifferent'], $infos['errors']);
+ }
+
+ /**
+ * @param array{result:string, isTransitionalDifferent:bool, errors:int} $properties
+ */
+ public static function __set_state(array $properties): self
+ {
+ return self::fromIntl($properties);
+ }
+
+ public function result(): string
+ {
+ return $this->result;
+ }
+
+ public function isTransitionalDifferent(): bool
+ {
+ return $this->isTransitionalDifferent;
+ }
+
+ public function errors(): int
+ {
+ return $this->errors;
+ }
+
+ public function error(int $error): ?string
+ {
+ return $this->errorList[$error] ?? null;
+ }
+
+ /**
+ * @return array
+ */
+ public function errorList(): array
+ {
+ return $this->errorList;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/LICENSE b/api_candidatos/vendor/league/uri/LICENSE
new file mode 100644
index 0000000..3b52528
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 ignace nyamagana butera
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/api_candidatos/vendor/league/uri/composer.json b/api_candidatos/vendor/league/uri/composer.json
new file mode 100644
index 0000000..dd60723
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/composer.json
@@ -0,0 +1,109 @@
+{
+ "name": "league/uri",
+ "type": "library",
+ "description" : "URI manipulation library",
+ "keywords": [
+ "url",
+ "uri",
+ "rfc3986",
+ "rfc3987",
+ "rfc6570",
+ "psr-7",
+ "parse_url",
+ "http",
+ "https",
+ "ws",
+ "ftp",
+ "data-uri",
+ "file-uri",
+ "middleware",
+ "parse_str",
+ "query-string",
+ "querystring",
+ "hostname",
+ "uri-template"
+ ],
+ "license": "MIT",
+ "homepage": "https://uri.thephpleague.com",
+ "authors": [
+ {
+ "name" : "Ignace Nyamagana Butera",
+ "email" : "nyamsprod@gmail.com",
+ "homepage" : "https://nyamsprod.com"
+ }
+ ],
+ "support": {
+ "forum": "https://thephpleague.slack.com",
+ "docs": "https://uri.thephpleague.com",
+ "issues": "https://github.com/thephpleague/uri/issues"
+ },
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nyamsprod"
+ }
+ ],
+ "require": {
+ "php": "^8.1",
+ "ext-json": "*",
+ "psr/http-message": "^1.0.1",
+ "league/uri-interfaces": "^2.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^v3.9.5",
+ "nyholm/psr7": "^1.5.1",
+ "php-http/psr7-integration-tests": "^1.1.1",
+ "phpbench/phpbench": "^1.2.6",
+ "phpstan/phpstan": "^1.8.5",
+ "phpstan/phpstan-deprecation-rules": "^1.0",
+ "phpstan/phpstan-phpunit": "^1.1.1",
+ "phpstan/phpstan-strict-rules": "^1.4.3",
+ "phpunit/phpunit": "^9.5.24",
+ "psr/http-factory": "^1.0.1"
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Uri\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "LeagueTest\\Uri\\": "tests"
+ }
+ },
+ "conflict": {
+ "league/uri-schemes": "^1.0"
+ },
+ "scripts": {
+ "benchmark": "phpbench run src --report=default",
+ "phpcs": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes --ansi",
+ "phpcs:fix": "php-cs-fixer fix -vvv --allow-risky=yes --ansi",
+ "phpstan": "phpstan analyse -l max -c phpstan.neon src --ansi --memory-limit=256M",
+ "phpunit": "XDEBUG_MODE=coverage phpunit --coverage-text",
+ "test": [
+ "@phpunit",
+ "@phpstan",
+ "@phpcs"
+ ]
+ },
+ "scripts-descriptions": {
+ "phpcs": "Runs coding style test suite",
+ "phpstan": "Runs complete codebase static analysis",
+ "phpunit": "Runs unit and functional testing",
+ "test": "Runs full test suite"
+ },
+ "suggest": {
+ "league/uri-components" : "Needed to easily manipulate URI objects",
+ "ext-intl" : "Needed to improve host validation",
+ "ext-fileinfo": "Needed to create Data URI from a filepath",
+ "psr/http-factory": "Needed to use the URI factory"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.x-dev"
+ }
+ },
+ "config": {
+ "sort-packages": true
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/Exceptions/TemplateCanNotBeExpanded.php b/api_candidatos/vendor/league/uri/src/Exceptions/TemplateCanNotBeExpanded.php
new file mode 100644
index 0000000..7c24b94
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/Exceptions/TemplateCanNotBeExpanded.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\Exceptions;
+
+use InvalidArgumentException;
+use League\Uri\Contracts\UriException;
+
+class TemplateCanNotBeExpanded extends InvalidArgumentException implements UriException
+{
+ public static function dueToUnableToProcessValueListWithPrefix(string $variableName): self
+ {
+ return new self('The ":" modifier can not be applied on "'.$variableName.'" since it is a list of values.');
+ }
+
+ public static function dueToNestedListOfValue(string $variableName): self
+ {
+ return new self('The "'.$variableName.'" can not be a nested list.');
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/Http.php b/api_candidatos/vendor/league/uri/src/Http.php
new file mode 100644
index 0000000..49551ae
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/Http.php
@@ -0,0 +1,269 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use JsonSerializable;
+use League\Uri\Contracts\UriInterface;
+use League\Uri\Exceptions\SyntaxError;
+use Psr\Http\Message\UriInterface as Psr7UriInterface;
+use Stringable;
+use function is_scalar;
+
+final class Http implements Psr7UriInterface, JsonSerializable
+{
+ private function __construct(private readonly UriInterface $uri)
+ {
+ $this->validate($this->uri);
+ }
+
+ /**
+ * Validate the submitted uri against PSR-7 UriInterface.
+ *
+ * @throws SyntaxError if the given URI does not follow PSR-7 UriInterface rules
+ */
+ private function validate(UriInterface $uri): void
+ {
+ if (null === $uri->getScheme() && '' === $uri->getHost()) {
+ throw new SyntaxError('An URI without scheme can not contains a empty host string according to PSR-7: '.$uri);
+ }
+
+ $port = $uri->getPort();
+ if (null !== $port && ($port < 0 || $port > 65535)) {
+ throw new SyntaxError('The URI port is outside the established TCP and UDP port ranges: '.$uri);
+ }
+ }
+
+ /**
+ * @param array{uri:UriInterface} $components
+ */
+ public static function __set_state(array $components): self
+ {
+ return new self($components['uri']);
+ }
+
+ /**
+ * Create a new instance from a string.
+ */
+ public static function createFromString(Stringable|UriInterface|String $uri = ''): self
+ {
+ return new self(Uri::createFromString($uri));
+ }
+
+ /**
+ * Create a new instance from a hash of parse_url parts.
+ *
+ * @param array $components a hash representation of the URI similar
+ * to PHP parse_url function result
+ */
+ public static function createFromComponents(array $components): self
+ {
+ return new self(Uri::createFromComponents($components));
+ }
+
+ /**
+ * Create a new instance from the environment.
+ */
+ public static function createFromServer(array $server): self
+ {
+ return new self(Uri::createFromServer($server));
+ }
+
+ /**
+ * Create a new instance from a URI and a Base URI.
+ *
+ * The returned URI must be absolute.
+ */
+ public static function createFromBaseUri(
+ Stringable|UriInterface|String $uri,
+ Stringable|UriInterface|String $base_uri = null
+ ): self {
+ return new self(Uri::createFromBaseUri($uri, $base_uri));
+ }
+
+ /**
+ * Create a new instance from a URI object.
+ */
+ public static function createFromUri(Psr7UriInterface|UriInterface $uri): self
+ {
+ if ($uri instanceof UriInterface) {
+ return new self($uri);
+ }
+
+ return new self(Uri::createFromUri($uri));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getScheme(): string
+ {
+ return (string) $this->uri->getScheme();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAuthority(): string
+ {
+ return (string) $this->uri->getAuthority();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getUserInfo(): string
+ {
+ return (string) $this->uri->getUserInfo();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getHost(): string
+ {
+ return (string) $this->uri->getHost();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getPort(): ?int
+ {
+ return $this->uri->getPort();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getPath(): string
+ {
+ return $this->uri->getPath();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getQuery(): string
+ {
+ return (string) $this->uri->getQuery();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getFragment(): string
+ {
+ return (string) $this->uri->getFragment();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function __toString(): string
+ {
+ return $this->uri->__toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function jsonSerialize(): string
+ {
+ return $this->uri->__toString();
+ }
+
+ /**
+ * Safely stringify input when possible for League UriInterface compatibility.
+ *
+ * @throws SyntaxError
+ */
+ private function filterInput(mixed $str): string|null
+ {
+ if (!is_scalar($str) && !$str instanceof Stringable) {
+ throw new SyntaxError('The component must be a string, a scalar or a Stringable object; `'.gettype($str).'` given.');
+ }
+
+ $str = (string) $str;
+ if ('' === $str) {
+ return null;
+ }
+
+ return $str;
+ }
+
+ private function newInstance(UriInterface $uri): self
+ {
+ if ((string) $uri === (string) $this->uri) {
+ return $this;
+ }
+
+ return new self($uri);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withScheme($scheme): self
+ {
+ return $this->newInstance($this->uri->withScheme($this->filterInput($scheme)));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withUserInfo($user, $password = null): self
+ {
+ return $this->newInstance($this->uri->withUserInfo($this->filterInput($user), $password));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withHost($host): self
+ {
+ return $this->newInstance($this->uri->withHost($this->filterInput($host)));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withPort($port): self
+ {
+ return $this->newInstance($this->uri->withPort($port));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withPath($path): self
+ {
+ return $this->newInstance($this->uri->withPath($path));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withQuery($query): self
+ {
+ return $this->newInstance($this->uri->withQuery($this->filterInput($query)));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withFragment($fragment): self
+ {
+ return $this->newInstance($this->uri->withFragment($this->filterInput($fragment)));
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/HttpFactory.php b/api_candidatos/vendor/league/uri/src/HttpFactory.php
new file mode 100644
index 0000000..fc3bcfa
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/HttpFactory.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use Psr\Http\Message\UriFactoryInterface;
+use Psr\Http\Message\UriInterface;
+
+final class HttpFactory implements UriFactoryInterface
+{
+ public function createUri(string $uri = ''): UriInterface
+ {
+ return Http::createFromString($uri);
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/Uri.php b/api_candidatos/vendor/league/uri/src/Uri.php
new file mode 100644
index 0000000..17e5611
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/Uri.php
@@ -0,0 +1,1316 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use finfo;
+use League\Uri\Contracts\UriInterface;
+use League\Uri\Exceptions\FileinfoSupportMissing;
+use League\Uri\Exceptions\IdnaConversionFailed;
+use League\Uri\Exceptions\IdnSupportMissing;
+use League\Uri\Exceptions\SyntaxError;
+use League\Uri\Idna\Idna;
+use Psr\Http\Message\UriInterface as Psr7UriInterface;
+use SensitiveParameter;
+use Stringable;
+use TypeError;
+use function array_filter;
+use function array_key_first;
+use function array_map;
+use function base64_decode;
+use function base64_encode;
+use function count;
+use function explode;
+use function file_get_contents;
+use function filter_var;
+use function implode;
+use function in_array;
+use function inet_pton;
+use function is_int;
+use function is_scalar;
+use function is_string;
+use function ltrim;
+use function preg_match;
+use function preg_replace;
+use function preg_replace_callback;
+use function rawurlencode;
+use function str_contains;
+use function str_replace;
+use function strlen;
+use function strpos;
+use function strspn;
+use function strtolower;
+use function substr;
+use const FILEINFO_MIME;
+use const FILTER_FLAG_IPV4;
+use const FILTER_FLAG_IPV6;
+use const FILTER_NULL_ON_FAILURE;
+use const FILTER_VALIDATE_BOOLEAN;
+use const FILTER_VALIDATE_IP;
+
+final class Uri implements UriInterface
+{
+ /**
+ * RFC3986 invalid characters.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-2.2
+ *
+ * @var string
+ */
+ private const REGEXP_INVALID_CHARS = '/[\x00-\x1f\x7f]/';
+
+ /**
+ * RFC3986 Sub delimiter characters regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-2.2
+ *
+ * @var string
+ */
+ private const REGEXP_CHARS_SUBDELIM = "\!\$&'\(\)\*\+,;\=%";
+
+ /**
+ * RFC3986 unreserved characters regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-2.3
+ *
+ * @var string
+ */
+ private const REGEXP_CHARS_UNRESERVED = 'A-Za-z\d_\-\.~';
+
+ /**
+ * RFC3986 schema regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.1
+ */
+ private const REGEXP_SCHEME = ',^[a-z]([-a-z\d+.]+)?$,i';
+
+ /**
+ * RFC3986 host identified by a registered name regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ private const REGEXP_HOST_REGNAME = '/^(
+ (?[a-z\d_~\-\.])|
+ (?[!$&\'()*+,;=])|
+ (?%[A-F\d]{2})
+ )+$/x';
+
+ /**
+ * RFC3986 delimiters of the generic URI components regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-2.2
+ */
+ private const REGEXP_HOST_GEN_DELIMS = '/[:\/?#\[\]@ ]/'; // Also includes space.
+
+ /**
+ * RFC3986 IPvFuture regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ private const REGEXP_HOST_IPFUTURE = '/^
+ v(?[A-F\d])+\.
+ (?:
+ (?[a-z\d_~\-\.])|
+ (?[!$&\'()*+,;=:]) # also include the : character
+ )+
+ $/ix';
+
+ /**
+ * RFC3986 IPvFuture host and port component.
+ */
+ private const REGEXP_HOST_PORT = ',^(?(\[.*]|[^:])*)(:(?[^/?#]*))?$,x';
+
+ /**
+ * Significant 10 bits of IP to detect Zone ID regular expression pattern.
+ */
+ private const HOST_ADDRESS_BLOCK = "\xfe\x80";
+
+ /**
+ * Regular expression pattern to for file URI.
+ * contains the volume but not the volume separator.
+ * The volume separator may be URL-encoded (`|` as `%7C`) by ::formatPath(),
+ * so we account for that here.
+ */
+ private const REGEXP_FILE_PATH = ',^(?/)?(?[a-zA-Z])(?:[:|\|]|%7C)(?.*)?,';
+
+ /**
+ * Mimetype regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc2397
+ */
+ private const REGEXP_MIMETYPE = ',^\w+/[-.\w]+(?:\+[-.\w]+)?$,';
+
+ /**
+ * Base64 content regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc2397
+ */
+ private const REGEXP_BINARY = ',(;|^)base64$,';
+
+ /**
+ * Windows file path string regular expression pattern.
+ * contains both the volume and volume separator.
+ */
+ private const REGEXP_WINDOW_PATH = ',^(?[a-zA-Z][:|\|]),';
+
+ /**
+ * Supported schemes and corresponding default port.
+ *
+ * @var array
+ */
+ private const SCHEME_DEFAULT_PORT = [
+ 'data' => null,
+ 'file' => null,
+ 'ftp' => 21,
+ 'gopher' => 70,
+ 'http' => 80,
+ 'https' => 443,
+ 'ws' => 80,
+ 'wss' => 443,
+ ];
+
+ /**
+ * Maximum number of formatted host cached.
+ *
+ * @var int
+ */
+ private const MAXIMUM_FORMATTED_HOST_CACHED = 100;
+
+ /**
+ * All ASCII letters sorted by typical frequency of occurrence.
+ *
+ * @var string
+ */
+ private const ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
+
+ private ?string $scheme;
+ private ?string $user_info;
+ private ?string $host;
+ private ?int $port;
+ private ?string $authority;
+ private string $path;
+ private ?string $query;
+ private ?string $fragment;
+ private ?string $uri;
+
+ private function __construct(
+ ?string $scheme,
+ ?string $user,
+ #[SensitiveParameter] ?string $pass,
+ ?string $host,
+ ?int $port,
+ string $path,
+ ?string $query,
+ ?string $fragment
+ ) {
+ $this->scheme = $this->formatScheme($scheme);
+ $this->user_info = $this->formatUserInfo($user, $pass);
+ $this->host = $this->formatHost($host);
+ $this->port = $this->formatPort($port);
+ $this->authority = $this->setAuthority();
+ $this->path = $this->formatPath($path);
+ $this->query = $this->formatQueryAndFragment($query);
+ $this->fragment = $this->formatQueryAndFragment($fragment);
+
+ $this->assertValidState();
+ }
+
+ /**
+ * Format the Scheme and Host component.
+ *
+ * @throws SyntaxError if the scheme is invalid
+ */
+ private function formatScheme(?string $scheme): ?string
+ {
+ if (null === $scheme || array_key_exists($scheme, self::SCHEME_DEFAULT_PORT)) {
+ return $scheme;
+ }
+
+ $formatted_scheme = strtolower($scheme);
+ if (array_key_exists($formatted_scheme, self::SCHEME_DEFAULT_PORT) || 1 === preg_match(self::REGEXP_SCHEME, $formatted_scheme)) {
+ return $formatted_scheme;
+ }
+
+ throw new SyntaxError('The scheme `'.$scheme.'` is invalid.');
+ }
+
+ /**
+ * Set the UserInfo component.
+ */
+ private function formatUserInfo(
+ ?string $user,
+ #[SensitiveParameter] ?string $password
+ ): ?string {
+ if (null === $user) {
+ return null;
+ }
+
+ static $user_pattern = '/[^%'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.']++|%(?![A-Fa-f\d]{2})/';
+ $user = preg_replace_callback($user_pattern, Uri::urlEncodeMatch(...), $user);
+ if (null === $password) {
+ return $user;
+ }
+
+ static $password_pattern = '/[^%:'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.']++|%(?![A-Fa-f\d]{2})/';
+
+ return $user.':'.preg_replace_callback($password_pattern, Uri::urlEncodeMatch(...), $password);
+ }
+
+ /**
+ * Returns the RFC3986 encoded string matched.
+ */
+ private static function urlEncodeMatch(array $matches): string
+ {
+ return rawurlencode($matches[0]);
+ }
+
+ /**
+ * Validate and Format the Host component.
+ */
+ private function formatHost(?string $host): ?string
+ {
+ if (null === $host || '' === $host) {
+ return $host;
+ }
+
+ static $formattedHostCache = [];
+ if (isset($formattedHostCache[$host])) {
+ return $formattedHostCache[$host];
+ }
+
+ $formattedHost = '[' === $host[0] ? $this->formatIp($host) : $this->formatRegisteredName($host);
+ $formattedHostCache[$host] = $formattedHost;
+ if (self::MAXIMUM_FORMATTED_HOST_CACHED < count($formattedHostCache)) {
+ unset($formattedHostCache[array_key_first($formattedHostCache)]);
+ }
+
+ return $formattedHost;
+ }
+
+ /**
+ * Validate and format a registered name.
+ *
+ * The host is converted to its ascii representation if needed
+ *
+ * @throws IdnSupportMissing if the submitted host required missing or misconfigured IDN support
+ * @throws SyntaxError if the submitted host is not a valid registered name
+ */
+ private function formatRegisteredName(string $host): string
+ {
+ $formatted_host = rawurldecode($host);
+ if (1 === preg_match(self::REGEXP_HOST_REGNAME, $formatted_host)) {
+ return $formatted_host;
+ }
+
+ if (1 === preg_match(self::REGEXP_HOST_GEN_DELIMS, $formatted_host)) {
+ throw new SyntaxError('The host `'.$host.'` is invalid : a registered name can not contain URI delimiters or spaces.');
+ }
+
+ $info = Idna::toAscii($host, Idna::IDNA2008_ASCII);
+ if (0 !== $info->errors()) {
+ throw IdnaConversionFailed::dueToIDNAError($host, $info);
+ }
+
+ return $info->result();
+ }
+
+ /**
+ * Validate and Format the IPv6/IPvfuture host.
+ *
+ * @throws SyntaxError if the submitted host is not a valid IP host
+ */
+ private function formatIp(string $host): string
+ {
+ $ip = substr($host, 1, -1);
+ if (false !== filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ return $host;
+ }
+
+ if (1 === preg_match(self::REGEXP_HOST_IPFUTURE, $ip, $matches) && !in_array($matches['version'], ['4', '6'], true)) {
+ return $host;
+ }
+
+ $pos = strpos($ip, '%');
+ if (false === $pos) {
+ throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
+ }
+
+ if (1 === preg_match(self::REGEXP_HOST_GEN_DELIMS, rawurldecode(substr($ip, $pos)))) {
+ throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
+ }
+
+ $ip = substr($ip, 0, $pos);
+ if (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
+ }
+
+ //Only the address block fe80::/10 can have a Zone ID attach to
+ //let's detect the link local significant 10 bits
+ if (str_starts_with((string)inet_pton($ip), self::HOST_ADDRESS_BLOCK)) {
+ return $host;
+ }
+
+ throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
+ }
+
+ /**
+ * Format the Port component.
+ *
+ * @throws SyntaxError
+ */
+ private function formatPort(Stringable|string|int|null $port = null): ?int
+ {
+ if (null === $port || '' === $port) {
+ return null;
+ }
+
+ if (!is_int($port) && !(is_string($port) && 1 === preg_match('/^\d*$/', $port))) {
+ throw new SyntaxError('The port is expected to be an integer or a string representing an integer; '.gettype($port).' given.');
+ }
+
+ $port = (int) $port;
+ if (0 > $port) {
+ throw new SyntaxError('The port `'.$port.'` is invalid.');
+ }
+
+ $defaultPort = self::SCHEME_DEFAULT_PORT[$this->scheme] ?? null;
+ if ($defaultPort === $port) {
+ return null;
+ }
+
+ return $port;
+ }
+
+ public static function __set_state(array $components): self
+ {
+ $components['user'] = null;
+ $components['pass'] = null;
+ if (null !== $components['user_info']) {
+ [$components['user'], $components['pass']] = explode(':', $components['user_info'], 2) + [1 => null];
+ }
+
+ return new self(
+ $components['scheme'],
+ $components['user'],
+ $components['pass'],
+ $components['host'],
+ $components['port'],
+ $components['path'],
+ $components['query'],
+ $components['fragment']
+ );
+ }
+
+ /**
+ * Creates a new instance from a URI and a Base URI.
+ *
+ * The returned URI must be absolute.
+ */
+ public static function createFromBaseUri(
+ Stringable|UriInterface|String $uri,
+ Stringable|UriInterface|String $base_uri = null
+ ): UriInterface {
+ if (!$uri instanceof UriInterface) {
+ $uri = self::createFromString($uri);
+ }
+
+ if (null === $base_uri) {
+ if (null === $uri->getScheme()) {
+ throw new SyntaxError('the URI `'.$uri.'` must be absolute.');
+ }
+
+ if (null === $uri->getAuthority()) {
+ return $uri;
+ }
+
+ /** @var UriInterface $uri */
+ $uri = UriResolver::resolve($uri, $uri->withFragment(null)->withQuery(null)->withPath(''));
+
+ return $uri;
+ }
+
+ if (!$base_uri instanceof UriInterface) {
+ $base_uri = self::createFromString($base_uri);
+ }
+
+ if (null === $base_uri->getScheme()) {
+ throw new SyntaxError('the base URI `'.$base_uri.'` must be absolute.');
+ }
+
+ /** @var UriInterface $uri */
+ $uri = UriResolver::resolve($uri, $base_uri);
+
+ return $uri;
+ }
+
+ /**
+ * Create a new instance from a string.
+ */
+ public static function createFromString(Stringable|string $uri = ''): self
+ {
+ $components = UriString::parse($uri);
+
+ return new self(
+ $components['scheme'],
+ $components['user'],
+ $components['pass'],
+ $components['host'],
+ $components['port'],
+ $components['path'],
+ $components['query'],
+ $components['fragment']
+ );
+ }
+
+ /**
+ * Create a new instance from a hash representation of the URI similar
+ * to PHP parse_url function result.
+ */
+ public static function createFromComponents(array $components = []): self
+ {
+ $components += [
+ 'scheme' => null, 'user' => null, 'pass' => null, 'host' => null,
+ 'port' => null, 'path' => '', 'query' => null, 'fragment' => null,
+ ];
+
+ return new self(
+ $components['scheme'],
+ $components['user'],
+ $components['pass'],
+ $components['host'],
+ $components['port'],
+ $components['path'],
+ $components['query'],
+ $components['fragment']
+ );
+ }
+
+ /**
+ * Create a new instance from a data file path.
+ *
+ * @param resource|null $context
+ *
+ * @throws FileinfoSupportMissing If ext/fileinfo is not installed
+ * @throws SyntaxError If the file does not exist or is not readable
+ */
+ public static function createFromDataPath(string $path, $context = null): self
+ {
+ static $finfo_support = null;
+ $finfo_support = $finfo_support ?? class_exists(finfo::class);
+
+ // @codeCoverageIgnoreStart
+ if (!$finfo_support) {
+ throw new FileinfoSupportMissing('Please install ext/fileinfo to use the '.__METHOD__.'() method.');
+ }
+ // @codeCoverageIgnoreEnd
+
+ $file_args = [$path, false];
+ $mime_args = [$path, FILEINFO_MIME];
+ if (null !== $context) {
+ $file_args[] = $context;
+ $mime_args[] = $context;
+ }
+
+ set_error_handler(fn (int $errno, string $errstr, string $errfile, int $errline) => true);
+ $raw = file_get_contents(...$file_args);
+ restore_error_handler();
+
+ if (false === $raw) {
+ throw new SyntaxError('The file `'.$path.'` does not exist or is not readable.');
+ }
+
+ $mimetype = (string) (new finfo(FILEINFO_MIME))->file(...$mime_args);
+
+ return Uri::createFromComponents([
+ 'scheme' => 'data',
+ 'path' => str_replace(' ', '', $mimetype.';base64,'.base64_encode($raw)),
+ ]);
+ }
+
+ /**
+ * Create a new instance from a Unix path string.
+ */
+ public static function createFromUnixPath(string $uri = ''): self
+ {
+ $uri = implode('/', array_map(rawurlencode(...), explode('/', $uri)));
+ if ('/' !== ($uri[0] ?? '')) {
+ return Uri::createFromComponents(['path' => $uri]);
+ }
+
+ return Uri::createFromComponents(['path' => $uri, 'scheme' => 'file', 'host' => '']);
+ }
+
+ /**
+ * Create a new instance from a local Windows path string.
+ */
+ public static function createFromWindowsPath(string $uri = ''): self
+ {
+ $root = '';
+ if (1 === preg_match(self::REGEXP_WINDOW_PATH, $uri, $matches)) {
+ $root = substr($matches['root'], 0, -1).':';
+ $uri = substr($uri, strlen($root));
+ }
+ $uri = str_replace('\\', '/', $uri);
+ $uri = implode('/', array_map(rawurlencode(...), explode('/', $uri)));
+
+ //Local Windows absolute path
+ if ('' !== $root) {
+ return Uri::createFromComponents(['path' => '/'.$root.$uri, 'scheme' => 'file', 'host' => '']);
+ }
+
+ //UNC Windows Path
+ if (!str_starts_with($uri, '//')) {
+ return Uri::createFromComponents(['path' => $uri]);
+ }
+
+ $parts = explode('/', substr($uri, 2), 2) + [1 => null];
+
+ return Uri::createFromComponents(['host' => $parts[0], 'path' => '/'.$parts[1], 'scheme' => 'file']);
+ }
+
+ /**
+ * Create a new instance from a URI object.
+ */
+ public static function createFromUri(Psr7UriInterface|UriInterface $uri): self
+ {
+ if ($uri instanceof UriInterface) {
+ $user_info = $uri->getUserInfo();
+ $user = null;
+ $pass = null;
+ if (null !== $user_info) {
+ [$user, $pass] = explode(':', $user_info, 2) + [1 => null];
+ }
+
+ return new self(
+ $uri->getScheme(),
+ $user,
+ $pass,
+ $uri->getHost(),
+ $uri->getPort(),
+ $uri->getPath(),
+ $uri->getQuery(),
+ $uri->getFragment()
+ );
+ }
+
+ $scheme = $uri->getScheme();
+ if ('' === $scheme) {
+ $scheme = null;
+ }
+
+ $fragment = $uri->getFragment();
+ if ('' === $fragment) {
+ $fragment = null;
+ }
+
+ $query = $uri->getQuery();
+ if ('' === $query) {
+ $query = null;
+ }
+
+ $host = $uri->getHost();
+ if ('' === $host) {
+ $host = null;
+ }
+
+ $user_info = $uri->getUserInfo();
+ $user = null;
+ $pass = null;
+ if ('' !== $user_info) {
+ [$user, $pass] = explode(':', $user_info, 2) + [1 => null];
+ }
+
+ return new self(
+ $scheme,
+ $user,
+ $pass,
+ $host,
+ $uri->getPort(),
+ $uri->getPath(),
+ $query,
+ $fragment
+ );
+ }
+
+ /**
+ * Create a new instance from the environment.
+ */
+ public static function createFromServer(array $server): self
+ {
+ $components = ['scheme' => self::fetchScheme($server)];
+ [$components['user'], $components['pass']] = self::fetchUserInfo($server);
+ [$components['host'], $components['port']] = self::fetchHostname($server);
+ [$components['path'], $components['query']] = self::fetchRequestUri($server);
+
+ return Uri::createFromComponents($components);
+ }
+
+ /**
+ * Returns the environment scheme.
+ */
+ private static function fetchScheme(array $server): string
+ {
+ $server += ['HTTPS' => ''];
+ $res = filter_var($server['HTTPS'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+
+ return false !== $res ? 'https' : 'http';
+ }
+
+ /**
+ * Returns the environment user info.
+ *
+ * @return non-empty-array{0:?string, 1:?string}
+ */
+ private static function fetchUserInfo(array $server): array
+ {
+ $server += ['PHP_AUTH_USER' => null, 'PHP_AUTH_PW' => null, 'HTTP_AUTHORIZATION' => ''];
+ $user = $server['PHP_AUTH_USER'];
+ $pass = $server['PHP_AUTH_PW'];
+ if (str_starts_with(strtolower($server['HTTP_AUTHORIZATION']), 'basic')) {
+ $userinfo = base64_decode(substr($server['HTTP_AUTHORIZATION'], 6), true);
+ if (false === $userinfo) {
+ throw new SyntaxError('The user info could not be detected');
+ }
+ [$user, $pass] = explode(':', $userinfo, 2) + [1 => null];
+ }
+
+ if (null !== $user) {
+ $user = rawurlencode($user);
+ }
+
+ if (null !== $pass) {
+ $pass = rawurlencode($pass);
+ }
+
+ return [$user, $pass];
+ }
+
+ /**
+ * Returns the environment host.
+ *
+ * @throws SyntaxError If the host can not be detected
+ *
+ * @return array{0:string|null, 1:int|null}
+ */
+ private static function fetchHostname(array $server): array
+ {
+ $server += ['SERVER_PORT' => null];
+ if (null !== $server['SERVER_PORT']) {
+ $server['SERVER_PORT'] = (int) $server['SERVER_PORT'];
+ }
+
+ if (isset($server['HTTP_HOST']) && 1 === preg_match(self::REGEXP_HOST_PORT, $server['HTTP_HOST'], $matches)) {
+ if (isset($matches['port'])) {
+ $matches['port'] = (int) $matches['port'];
+ }
+
+ return [
+ $matches['host'],
+ $matches['port'] ?? $server['SERVER_PORT'],
+ ];
+ }
+
+ if (!isset($server['SERVER_ADDR'])) {
+ throw new SyntaxError('The host could not be detected');
+ }
+
+ if (false === filter_var($server['SERVER_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
+ $server['SERVER_ADDR'] = '['.$server['SERVER_ADDR'].']';
+ }
+
+ return [$server['SERVER_ADDR'], $server['SERVER_PORT']];
+ }
+
+ /**
+ * Returns the environment path.
+ *
+ * @return non-empty-array{0:?string, 1:?string}
+ */
+ private static function fetchRequestUri(array $server): array
+ {
+ $server += ['IIS_WasUrlRewritten' => null, 'UNENCODED_URL' => '', 'PHP_SELF' => '', 'QUERY_STRING' => null];
+ if ('1' === $server['IIS_WasUrlRewritten'] && '' !== $server['UNENCODED_URL']) {
+ return explode('?', $server['UNENCODED_URL'], 2) + [1 => null];
+ }
+
+ if (isset($server['REQUEST_URI'])) {
+ [$path] = explode('?', $server['REQUEST_URI'], 2);
+ $query = ('' !== $server['QUERY_STRING']) ? $server['QUERY_STRING'] : null;
+
+ return [$path, $query];
+ }
+
+ return [$server['PHP_SELF'], $server['QUERY_STRING']];
+ }
+
+ /**
+ * Generate the URI authority part.
+ */
+ private function setAuthority(): ?string
+ {
+ $authority = null;
+ if (null !== $this->user_info) {
+ $authority = $this->user_info.'@';
+ }
+
+ if (null !== $this->host) {
+ $authority .= $this->host;
+ }
+
+ if (null !== $this->port) {
+ $authority .= ':'.$this->port;
+ }
+
+ return $authority;
+ }
+
+ /**
+ * Format the Path component.
+ */
+ private function formatPath(string $path): string
+ {
+ if ('data' === $this->scheme) {
+ $path = $this->formatDataPath($path);
+ }
+
+ if ('/' !== $path) {
+ static $pattern = '/[^'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.':@\/}{]++|%(?![A-Fa-f\d]{2})/';
+
+ $path = (string) preg_replace_callback($pattern, Uri::urlEncodeMatch(...), $path);
+ }
+
+ if ('file' === $this->scheme) {
+ $path = $this->formatFilePath($path);
+ }
+
+ return $path;
+ }
+
+ /**
+ * Filter the Path component.
+ *
+ * @link https://tools.ietf.org/html/rfc2397
+ *
+ * @throws SyntaxError If the path is not compliant with RFC2397
+ */
+ private function formatDataPath(string $path): string
+ {
+ if ('' == $path) {
+ return 'text/plain;charset=us-ascii,';
+ }
+
+ if (strlen($path) !== strspn($path, self::ASCII) || !str_contains($path, ',')) {
+ throw new SyntaxError('The path `'.$path.'` is invalid according to RFC2937.');
+ }
+
+ $parts = explode(',', $path, 2) + [1 => null];
+ $mediatype = explode(';', (string) $parts[0], 2) + [1 => null];
+ $data = (string) $parts[1];
+ $mimetype = $mediatype[0];
+ if (null === $mimetype || '' === $mimetype) {
+ $mimetype = 'text/plain';
+ }
+
+ $parameters = $mediatype[1];
+ if (null === $parameters || '' === $parameters) {
+ $parameters = 'charset=us-ascii';
+ }
+
+ $this->assertValidPath($mimetype, $parameters, $data);
+
+ return $mimetype.';'.$parameters.','.$data;
+ }
+
+ /**
+ * Assert the path is a compliant with RFC2397.
+ *
+ * @link https://tools.ietf.org/html/rfc2397
+ *
+ * @throws SyntaxError If the mediatype or the data are not compliant with the RFC2397
+ */
+ private function assertValidPath(string $mimetype, string $parameters, string $data): void
+ {
+ if (1 !== preg_match(self::REGEXP_MIMETYPE, $mimetype)) {
+ throw new SyntaxError('The path mimetype `'.$mimetype.'` is invalid.');
+ }
+
+ $is_binary = 1 === preg_match(self::REGEXP_BINARY, $parameters, $matches);
+ if ($is_binary) {
+ $parameters = substr($parameters, 0, - strlen($matches[0]));
+ }
+
+ $res = array_filter(array_filter(explode(';', $parameters), $this->validateParameter(...)));
+ if ([] !== $res) {
+ throw new SyntaxError('The path paremeters `'.$parameters.'` is invalid.');
+ }
+
+ if (!$is_binary) {
+ return;
+ }
+
+ $res = base64_decode($data, true);
+ if (false === $res || $data !== base64_encode($res)) {
+ throw new SyntaxError('The path data `'.$data.'` is invalid.');
+ }
+ }
+
+ /**
+ * Validate mediatype parameter.
+ */
+ private function validateParameter(string $parameter): bool
+ {
+ $properties = explode('=', $parameter);
+
+ return 2 != count($properties) || 'base64' === strtolower($properties[0]);
+ }
+
+ /**
+ * Format path component for file scheme.
+ */
+ private function formatFilePath(string $path): string
+ {
+ $replace = static function (array $matches): string {
+ return $matches['delim'].$matches['volume'].':'.$matches['rest'];
+ };
+
+ return (string) preg_replace_callback(self::REGEXP_FILE_PATH, $replace, $path);
+ }
+
+ /**
+ * Format the Query or the Fragment component.
+ *
+ * Returns a array containing:
+ *
+ *
the formatted component (a string or null)
+ *
a boolean flag telling wether the delimiter is to be added to the component
+ * when building the URI string representation
+ *
+ */
+ private function formatQueryAndFragment(?string $component): ?string
+ {
+ if (null === $component || '' === $component) {
+ return $component;
+ }
+
+ static $pattern = '/[^'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.':@\/?]++|%(?![A-Fa-f\d]{2})/';
+ return preg_replace_callback($pattern, Uri::urlEncodeMatch(...), $component);
+ }
+
+ /**
+ * assert the URI internal state is valid.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3
+ * @link https://tools.ietf.org/html/rfc3986#section-3.3
+ *
+ * @throws SyntaxError if the URI is in an invalid state according to RFC3986
+ * @throws SyntaxError if the URI is in an invalid state according to scheme specific rules
+ */
+ private function assertValidState(): void
+ {
+ if (null !== $this->authority && ('' !== $this->path && '/' !== $this->path[0])) {
+ throw new SyntaxError('If an authority is present the path must be empty or start with a `/`.');
+ }
+
+ if (null === $this->authority && str_starts_with($this->path, '//')) {
+ throw new SyntaxError('If there is no authority the path `'.$this->path.'` can not start with a `//`.');
+ }
+
+ $pos = strpos($this->path, ':');
+ if (null === $this->authority
+ && null === $this->scheme
+ && false !== $pos
+ && !str_contains(substr($this->path, 0, $pos), '/')
+ ) {
+ throw new SyntaxError('In absence of a scheme and an authority the first path segment cannot contain a colon (":") character.');
+ }
+
+ $this->uri = null;
+
+ if (! match ($this->scheme) {
+ 'data' => $this->isUriWithSchemeAndPathOnly(),
+ 'file' => $this->isUriWithSchemeHostAndPathOnly(),
+ 'ftp', 'gopher' => $this->isNonEmptyHostUriWithoutFragmentAndQuery(),
+ 'http', 'https' => $this->isNonEmptyHostUri(),
+ 'ws', 'wss' => $this->isNonEmptyHostUriWithoutFragment(),
+ default => true,
+ }) {
+ throw new SyntaxError('The uri `'.$this.'` is invalid for the `'.$this->scheme.'` scheme.');
+ }
+ }
+
+ /**
+ * URI validation for URI schemes which allows only scheme and path components.
+ */
+ private function isUriWithSchemeAndPathOnly(): bool
+ {
+ return null === $this->authority
+ && null === $this->query
+ && null === $this->fragment;
+ }
+
+ /**
+ * URI validation for URI schemes which allows only scheme, host and path components.
+ */
+ private function isUriWithSchemeHostAndPathOnly(): bool
+ {
+ return null === $this->user_info
+ && null === $this->port
+ && null === $this->query
+ && null === $this->fragment
+ && !('' != $this->scheme && null === $this->host);
+ }
+
+ /**
+ * URI validation for URI schemes which disallow the empty '' host.
+ */
+ private function isNonEmptyHostUri(): bool
+ {
+ return '' !== $this->host
+ && !(null !== $this->scheme && null === $this->host);
+ }
+
+ /**
+ * URI validation for URIs schemes which disallow the empty '' host
+ * and forbids the fragment component.
+ */
+ private function isNonEmptyHostUriWithoutFragment(): bool
+ {
+ return $this->isNonEmptyHostUri() && null === $this->fragment;
+ }
+
+ /**
+ * URI validation for URIs schemes which disallow the empty '' host
+ * and forbids fragment and query components.
+ */
+ private function isNonEmptyHostUriWithoutFragmentAndQuery(): bool
+ {
+ return $this->isNonEmptyHostUri() && null === $this->fragment && null === $this->query;
+ }
+
+ /**
+ * Generate the URI string representation from its components.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5.3
+ */
+ private function getUriString(
+ ?string $scheme,
+ ?string $authority,
+ string $path,
+ ?string $query,
+ ?string $fragment
+ ): string {
+ if (null !== $scheme) {
+ $scheme = $scheme.':';
+ }
+
+ if (null !== $authority) {
+ $authority = '//'.$authority;
+ }
+
+ if (null !== $query) {
+ $query = '?'.$query;
+ }
+
+ if (null !== $fragment) {
+ $fragment = '#'.$fragment;
+ }
+
+ return $scheme.$authority.$path.$query.$fragment;
+ }
+
+ public function toString(): string
+ {
+ return $this->uri ??= $this->getUriString(
+ $this->scheme,
+ $this->authority,
+ $this->path,
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function __toString(): string
+ {
+ return $this->toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function jsonSerialize(): string
+ {
+ return $this->toString();
+ }
+
+ /**
+ * @return array{
+ * scheme:?string,
+ * user_info:?string,
+ * host:?string,
+ * port:?int,
+ * path:string,
+ * query:?string,
+ * fragment:?string
+ * }
+ */
+ public function __debugInfo(): array
+ {
+ return [
+ 'scheme' => $this->scheme,
+ 'user_info' => isset($this->user_info) ? preg_replace(',:(.*).?$,', ':***', $this->user_info) : null,
+ 'host' => $this->host,
+ 'port' => $this->port,
+ 'path' => $this->path,
+ 'query' => $this->query,
+ 'fragment' => $this->fragment,
+ ];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getScheme(): ?string
+ {
+ return $this->scheme;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAuthority(): ?string
+ {
+ return $this->authority;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getUserInfo(): ?string
+ {
+ return $this->user_info;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getHost(): ?string
+ {
+ return $this->host;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getPort(): ?int
+ {
+ return $this->port;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getPath(): string
+ {
+ if (str_starts_with($this->path, '//')) {
+ return '/'.ltrim($this->path, '/');
+ }
+
+ return $this->path;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getQuery(): ?string
+ {
+ return $this->query;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getFragment(): ?string
+ {
+ return $this->fragment;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withScheme($scheme): UriInterface
+ {
+ $scheme = $this->formatScheme($this->filterString($scheme));
+ if ($scheme === $this->scheme) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->scheme = $scheme;
+ $clone->port = $clone->formatPort($clone->port);
+ $clone->authority = $clone->setAuthority();
+ $clone->assertValidState();
+
+ return $clone;
+ }
+
+ /**
+ * Filter a string.
+ *
+ * @param mixed $str the value to evaluate as a string
+ *
+ * @throws SyntaxError if the submitted data can not be converted to string
+ */
+ private function filterString(mixed $str): ?string
+ {
+ if (null === $str) {
+ return null;
+ }
+
+ if (!is_scalar($str) && !$str instanceof Stringable) {
+ throw new SyntaxError('The component must be a string, a scalar or a Stringable object; `'.gettype($str).'` given.');
+ }
+
+ $str = (string) $str;
+ if (1 !== preg_match(self::REGEXP_INVALID_CHARS, $str)) {
+ return $str;
+ }
+
+ throw new SyntaxError('The component `'.$str.'` contains invalid characters.');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withUserInfo(
+ $user,
+ #[SensitiveParameter] $password = null
+ ): UriInterface {
+ $user_info = null;
+ $user = $this->filterString($user);
+ if (null !== $password) {
+ $password = $this->filterString($password);
+ }
+
+ if ('' !== $user) {
+ $user_info = $this->formatUserInfo($user, $password);
+ }
+
+ if ($user_info === $this->user_info) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->user_info = $user_info;
+ $clone->authority = $clone->setAuthority();
+ $clone->assertValidState();
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withHost($host): UriInterface
+ {
+ $host = $this->formatHost($this->filterString($host));
+ if ($host === $this->host) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->host = $host;
+ $clone->authority = $clone->setAuthority();
+ $clone->assertValidState();
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withPort($port): UriInterface
+ {
+ $port = $this->formatPort($port);
+ if ($port === $this->port) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->port = $port;
+ $clone->authority = $clone->setAuthority();
+ $clone->assertValidState();
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param string|object $path
+ */
+ public function withPath($path): UriInterface
+ {
+ $path = $this->filterString($path);
+ if (null === $path) {
+ throw new TypeError('A path must be a string NULL given.');
+ }
+
+ $path = $this->formatPath($path);
+ if ($path === $this->path) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->path = $path;
+ $clone->assertValidState();
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withQuery($query): UriInterface
+ {
+ $query = $this->formatQueryAndFragment($this->filterString($query));
+ if ($query === $this->query) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->query = $query;
+ $clone->assertValidState();
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function withFragment($fragment): UriInterface
+ {
+ $fragment = $this->formatQueryAndFragment($this->filterString($fragment));
+ if ($fragment === $this->fragment) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->fragment = $fragment;
+ $clone->assertValidState();
+
+ return $clone;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriInfo.php b/api_candidatos/vendor/league/uri/src/UriInfo.php
new file mode 100644
index 0000000..83fa77e
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriInfo.php
@@ -0,0 +1,169 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use League\Uri\Contracts\UriInterface;
+use Psr\Http\Message\UriInterface as Psr7UriInterface;
+use function explode;
+use function implode;
+use function preg_replace_callback;
+use function rawurldecode;
+
+final class UriInfo
+{
+ private const REGEXP_ENCODED_CHARS = ',%(2[D|E]|3\d|4[1-9|A-F]|5[\d|A|F]|6[1-9|A-F]|7[\d|E]),i';
+ private const WHATWG_SPECIAL_SCHEMES = ['ftp', 'http', 'https', 'ws', 'wss'];
+
+ /**
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
+
+ private static function emptyComponentValue(Psr7UriInterface|UriInterface $uri): ?string
+ {
+ return $uri instanceof Psr7UriInterface ? '' : null;
+ }
+
+ /**
+ * Normalizes an URI for comparison.
+ */
+ private static function normalize(Psr7UriInterface|UriInterface $uri): Psr7UriInterface|UriInterface
+ {
+ $null = self::emptyComponentValue($uri);
+
+ $path = $uri->getPath();
+ if ('/' === ($path[0] ?? '') || '' !== $uri->getScheme().$uri->getAuthority()) {
+ $path = UriResolver::resolve($uri, $uri->withPath('')->withQuery($null))->getPath();
+ }
+
+ $query = $uri->getQuery();
+ $fragment = $uri->getFragment();
+ $fragmentOrig = $fragment;
+ $pairs = null === $query ? [] : explode('&', $query);
+ sort($pairs, SORT_REGULAR);
+
+ $replace = static fn (array $matches): string => rawurldecode($matches[0]);
+
+ $retval = preg_replace_callback(self::REGEXP_ENCODED_CHARS, $replace, [$path, implode('&', $pairs), $fragment]);
+ if (null !== $retval) {
+ [$path, $query, $fragment] = $retval + ['', $null, $null];
+ }
+
+ if ($null !== $uri->getAuthority() && '' === $path) {
+ $path = '/';
+ }
+
+ return $uri
+ ->withHost(Uri::createFromComponents(['host' => $uri->getHost()])->getHost())
+ ->withPath($path)
+ ->withQuery([] === $pairs ? $null : $query)
+ ->withFragment($null === $fragmentOrig ? $fragmentOrig : $fragment);
+ }
+
+ /**
+ * Tells whether the URI represents an absolute URI.
+ */
+ public static function isAbsolute(Psr7UriInterface|UriInterface $uri): bool
+ {
+ return self::emptyComponentValue($uri) !== $uri->getScheme();
+ }
+
+ /**
+ * Tell whether the URI represents a network path.
+ */
+ public static function isNetworkPath(Psr7UriInterface|UriInterface $uri): bool
+ {
+ $null = self::emptyComponentValue($uri);
+
+ return $null === $uri->getScheme() && $null !== $uri->getAuthority();
+ }
+
+ /**
+ * Tells whether the URI represents an absolute path.
+ */
+ public static function isAbsolutePath(Psr7UriInterface|UriInterface $uri): bool
+ {
+ $null = self::emptyComponentValue($uri);
+
+ return $null === $uri->getScheme()
+ && $null === $uri->getAuthority()
+ && '/' === ($uri->getPath()[0] ?? '');
+ }
+
+ /**
+ * Tell whether the URI represents a relative path.
+ *
+ */
+ public static function isRelativePath(Psr7UriInterface|UriInterface $uri): bool
+ {
+ $null = self::emptyComponentValue($uri);
+
+ return $null === $uri->getScheme()
+ && $null === $uri->getAuthority()
+ && '/' !== ($uri->getPath()[0] ?? '');
+ }
+
+ /**
+ * Tells whether both URI refers to the same document.
+ */
+ public static function isSameDocument(Psr7UriInterface|UriInterface $uri, Psr7UriInterface|UriInterface $base_uri): bool
+ {
+ $uri = self::normalize($uri);
+ $base_uri = self::normalize($base_uri);
+
+ return (string) $uri->withFragment($uri instanceof Psr7UriInterface ? '' : null)
+ === (string) $base_uri->withFragment($base_uri instanceof Psr7UriInterface ? '' : null);
+ }
+
+ /**
+ * Returns the URI origin property as defined by WHATWG URL living standard.
+ *
+ * {@see https://url.spec.whatwg.org/#origin}
+ *
+ * For URI without a special scheme the method returns null
+ * For URI with the file scheme the method will return null (as this is left to the implementation decision)
+ * For URI with a special scheme the method returns the scheme followed by its authority (without the userinfo part)
+ */
+ public static function getOrigin(Psr7UriInterface|UriInterface $uri): ?string
+ {
+ $scheme = $uri->getScheme();
+ if ('blob' === $scheme) {
+ $uri = Uri::createFromString($uri->getPath());
+ $scheme = $uri->getScheme();
+ }
+
+ if (in_array($scheme, self::WHATWG_SPECIAL_SCHEMES, true)) {
+ $null = self::emptyComponentValue($uri);
+
+ return (string) $uri->withFragment($null)->withQuery($null)->withPath('')->withUserInfo($null, null);
+ }
+
+ return null;
+ }
+
+ /**
+ * Tells whether two URI do not share the same origin.
+ *
+ * @see UriInfo::getOrigin()
+ */
+ public static function isCrossOrigin(Psr7UriInterface|UriInterface $uri, Psr7UriInterface|UriInterface $base_uri): bool
+ {
+ return null === ($uriString = self::getOrigin(Uri::createFromUri($uri)))
+ || null === ($baseUriString = self::getOrigin(Uri::createFromUri($base_uri)))
+ || $uriString !== $baseUriString;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriResolver.php b/api_candidatos/vendor/league/uri/src/UriResolver.php
new file mode 100644
index 0000000..844a3d3
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriResolver.php
@@ -0,0 +1,342 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use League\Uri\Contracts\UriInterface;
+use Psr\Http\Message\UriInterface as Psr7UriInterface;
+use function array_pop;
+use function array_reduce;
+use function count;
+use function end;
+use function explode;
+use function implode;
+use function in_array;
+use function str_repeat;
+use function strpos;
+use function substr;
+
+final class UriResolver
+{
+ /**
+ * @var array
+ */
+ const DOT_SEGMENTS = ['.' => 1, '..' => 1];
+
+ /**
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Resolves an URI against a base URI using RFC3986 rules.
+ *
+ * If the first argument is a UriInterface the method returns a UriInterface object
+ * If the first argument is a Psr7UriInterface the method returns a Psr7UriInterface object
+ */
+ public static function resolve(Psr7UriInterface|UriInterface $uri, Psr7UriInterface|UriInterface $base_uri): Psr7UriInterface|UriInterface
+ {
+ $null = $uri instanceof Psr7UriInterface ? '' : null;
+
+ if ($null !== $uri->getScheme()) {
+ return $uri
+ ->withPath(self::removeDotSegments($uri->getPath()));
+ }
+
+ if ($null !== $uri->getAuthority()) {
+ return $uri
+ ->withScheme($base_uri->getScheme())
+ ->withPath(self::removeDotSegments($uri->getPath()));
+ }
+
+ $user = $null;
+ $pass = null;
+ $userInfo = $base_uri->getUserInfo();
+ if (null !== $userInfo) {
+ [$user, $pass] = explode(':', $userInfo, 2) + [1 => null];
+ }
+
+ [$uri_path, $uri_query] = self::resolvePathAndQuery($uri, $base_uri);
+
+ return $uri
+ ->withPath(self::removeDotSegments($uri_path))
+ ->withQuery($uri_query)
+ ->withHost($base_uri->getHost())
+ ->withPort($base_uri->getPort())
+ ->withUserInfo((string) $user, $pass)
+ ->withScheme($base_uri->getScheme())
+ ;
+ }
+
+ /**
+ * Remove dot segments from the URI path.
+ */
+ private static function removeDotSegments(string $path): string
+ {
+ if (!str_contains($path, '.')) {
+ return $path;
+ }
+
+ $old_segments = explode('/', $path);
+ $new_path = implode('/', array_reduce($old_segments, UriResolver::reducer(...), []));
+ if (isset(self::DOT_SEGMENTS[end($old_segments)])) {
+ $new_path .= '/';
+ }
+
+ // @codeCoverageIgnoreStart
+ // added because some PSR-7 implementations do not respect RFC3986
+ if (str_starts_with($path, '/') && !str_starts_with($new_path, '/')) {
+ return '/'.$new_path;
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $new_path;
+ }
+
+ /**
+ * Remove dot segments.
+ *
+ * @return array
+ */
+ private static function reducer(array $carry, string $segment): array
+ {
+ if ('..' === $segment) {
+ array_pop($carry);
+
+ return $carry;
+ }
+
+ if (!isset(self::DOT_SEGMENTS[$segment])) {
+ $carry[] = $segment;
+ }
+
+ return $carry;
+ }
+
+ /**
+ * Resolves an URI path and query component.
+ *
+ * @return array{0:string, 1:string|null}
+ */
+ private static function resolvePathAndQuery(
+ Psr7UriInterface|UriInterface $uri,
+ Psr7UriInterface|UriInterface $base_uri
+ ): array {
+ $target_path = $uri->getPath();
+ $target_query = $uri->getQuery();
+ $null = $uri instanceof Psr7UriInterface ? '' : null;
+ $baseNull = $base_uri instanceof Psr7UriInterface ? '' : null;
+
+ if (str_starts_with($target_path, '/')) {
+ return [$target_path, $target_query];
+ }
+
+ if ('' === $target_path) {
+ if ($null === $target_query) {
+ $target_query = $base_uri->getQuery();
+ }
+
+ $target_path = $base_uri->getPath();
+ //@codeCoverageIgnoreStart
+ //because some PSR-7 Uri implementations allow this RFC3986 forbidden construction
+ if ($baseNull !== $base_uri->getAuthority() && !str_starts_with($target_path, '/')) {
+ $target_path = '/'.$target_path;
+ }
+ //@codeCoverageIgnoreEnd
+
+ return [$target_path, $target_query];
+ }
+
+ $base_path = $base_uri->getPath();
+ if ($baseNull !== $base_uri->getAuthority() && '' === $base_path) {
+ $target_path = '/'.$target_path;
+ }
+
+ if ('' !== $base_path) {
+ $segments = explode('/', $base_path);
+ array_pop($segments);
+ if ([] !== $segments) {
+ $target_path = implode('/', $segments).'/'.$target_path;
+ }
+ }
+
+ return [$target_path, $target_query];
+ }
+
+ /**
+ * Relativizes an URI according to a base URI.
+ *
+ * This method MUST retain the state of the submitted URI instance, and return
+ * an URI instance of the same type that contains the applied modifications.
+ *
+ * This method MUST be transparent when dealing with error and exceptions.
+ * It MUST not alter of silence them apart from validating its own parameters.
+ */
+ public static function relativize(
+ Psr7UriInterface|UriInterface $uri,
+ Psr7UriInterface|UriInterface $base_uri
+ ): Psr7UriInterface|UriInterface {
+ $uri = self::formatHost($uri);
+ $base_uri = self::formatHost($base_uri);
+ if (!self::isRelativizable($uri, $base_uri)) {
+ return $uri;
+ }
+
+ $null = $uri instanceof Psr7UriInterface ? '' : null;
+ $uri = $uri->withScheme($null)->withPort(null)->withUserInfo($null)->withHost($null);
+ $target_path = $uri->getPath();
+ if ($target_path !== $base_uri->getPath()) {
+ return $uri->withPath(self::relativizePath($target_path, $base_uri->getPath()));
+ }
+
+ if (self::componentEquals('query', $uri, $base_uri)) {
+ return $uri->withPath('')->withQuery($null);
+ }
+
+ if ($null === $uri->getQuery()) {
+ return $uri->withPath(self::formatPathWithEmptyBaseQuery($target_path));
+ }
+
+ return $uri->withPath('');
+ }
+
+ /**
+ * Tells whether the component value from both URI object equals.
+ */
+ private static function componentEquals(
+ string $property,
+ Psr7UriInterface|UriInterface $uri,
+ Psr7UriInterface|UriInterface $base_uri
+ ): bool {
+ return self::getComponent($property, $uri) === self::getComponent($property, $base_uri);
+ }
+
+ /**
+ * Returns the component value from the submitted URI object.
+ */
+ private static function getComponent(string $property, Psr7UriInterface|UriInterface $uri): ?string
+ {
+ $component = match ($property) {
+ 'query' => $uri->getQuery(),
+ 'authority' => $uri->getAuthority(),
+ default => $uri->getScheme(), //scheme
+ };
+
+ if ($uri instanceof Psr7UriInterface && '' === $component) {
+ return null;
+ }
+
+ return $component;
+ }
+
+ /**
+ * Filter the URI object.
+ */
+ private static function formatHost(Psr7UriInterface|UriInterface $uri): Psr7UriInterface|UriInterface
+ {
+ if (!$uri instanceof Psr7UriInterface) {
+ return $uri;
+ }
+
+ $host = $uri->getHost();
+ if ('' === $host) {
+ return $uri;
+ }
+
+ return $uri->withHost((string) Uri::createFromComponents(['host' => $host])->getHost());
+ }
+
+ /**
+ * Tells whether the submitted URI object can be relativize.
+ */
+ private static function isRelativizable(
+ Psr7UriInterface|UriInterface $uri,
+ Psr7UriInterface|UriInterface $base_uri
+ ): bool {
+ return !UriInfo::isRelativePath($uri)
+ && self::componentEquals('scheme', $uri, $base_uri)
+ && self::componentEquals('authority', $uri, $base_uri);
+ }
+
+ /**
+ * Relatives the URI for an authority-less target URI.
+ */
+ private static function relativizePath(string $path, string $basepath): string
+ {
+ $base_segments = self::getSegments($basepath);
+ $target_segments = self::getSegments($path);
+ $target_basename = array_pop($target_segments);
+ array_pop($base_segments);
+ foreach ($base_segments as $offset => $segment) {
+ if (!isset($target_segments[$offset]) || $segment !== $target_segments[$offset]) {
+ break;
+ }
+ unset($base_segments[$offset], $target_segments[$offset]);
+ }
+ $target_segments[] = $target_basename;
+
+ return self::formatPath(
+ str_repeat('../', count($base_segments)).implode('/', $target_segments),
+ $basepath
+ );
+ }
+
+ /**
+ * returns the path segments.
+ *
+ * @return string[]
+ */
+ private static function getSegments(string $path): array
+ {
+ if ('' !== $path && '/' === $path[0]) {
+ $path = substr($path, 1);
+ }
+
+ return explode('/', $path);
+ }
+
+ /**
+ * Formatting the path to keep a valid URI.
+ */
+ private static function formatPath(string $path, string $basepath): string
+ {
+ if ('' === $path) {
+ return in_array($basepath, ['', '/'], true) ? $basepath : './';
+ }
+
+ if (false === ($colon_pos = strpos($path, ':'))) {
+ return $path;
+ }
+
+ $slash_pos = strpos($path, '/');
+ if (false === $slash_pos || $colon_pos < $slash_pos) {
+ return "./$path";
+ }
+
+ return $path;
+ }
+
+ /**
+ * Formatting the path to keep a resolvable URI.
+ */
+ private static function formatPathWithEmptyBaseQuery(string $path): string
+ {
+ $target_segments = self::getSegments($path);
+ /** @var string $basename */
+ $basename = end($target_segments);
+
+ return '' === $basename ? './' : $basename;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriString.php b/api_candidatos/vendor/league/uri/src/UriString.php
new file mode 100644
index 0000000..93dd928
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriString.php
@@ -0,0 +1,436 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use League\Uri\Exceptions\IdnaConversionFailed;
+use League\Uri\Exceptions\IdnSupportMissing;
+use League\Uri\Exceptions\SyntaxError;
+use League\Uri\Idna\Idna;
+use Stringable;
+use function array_merge;
+use function explode;
+use function filter_var;
+use function inet_pton;
+use function preg_match;
+use function rawurldecode;
+use function sprintf;
+use function strpos;
+use function substr;
+use const FILTER_FLAG_IPV6;
+use const FILTER_VALIDATE_IP;
+
+/**
+ * A class to parse a URI string according to RFC3986.
+ *
+ * @link https://tools.ietf.org/html/rfc3986
+ * @package League\Uri
+ * @author Ignace Nyamagana Butera
+ * @since 6.0.0
+ */
+final class UriString
+{
+ /**
+ * Default URI component values.
+ */
+ private const URI_COMPONENTS = [
+ 'scheme' => null, 'user' => null, 'pass' => null, 'host' => null,
+ 'port' => null, 'path' => '', 'query' => null, 'fragment' => null,
+ ];
+
+ /**
+ * Simple URI which do not need any parsing.
+ */
+ private const URI_SCHORTCUTS = [
+ '' => [],
+ '#' => ['fragment' => ''],
+ '?' => ['query' => ''],
+ '?#' => ['query' => '', 'fragment' => ''],
+ '/' => ['path' => '/'],
+ '//' => ['host' => ''],
+ ];
+
+ /**
+ * Range of invalid characters in URI string.
+ */
+ private const REGEXP_INVALID_URI_CHARS = '/[\x00-\x1f\x7f]/';
+
+ /**
+ * RFC3986 regular expression URI splitter.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#appendix-B
+ */
+ private const REGEXP_URI_PARTS = ',^
+ (?(?[^:/?\#]+):)? # URI scheme component
+ (?//(?[^/?\#]*))? # URI authority part
+ (?[^?\#]*) # URI path component
+ (?\?(?[^\#]*))? # URI query component
+ (?\#(?.*))? # URI fragment component
+ ,x';
+
+ /**
+ * URI scheme regular expresssion.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.1
+ */
+ private const REGEXP_URI_SCHEME = '/^([a-z][a-z\d+.-]*)?$/i';
+
+ /**
+ * IPvFuture regular expression.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ private const REGEXP_IP_FUTURE = '/^
+ v(?[A-F0-9])+\.
+ (?:
+ (?[a-z0-9_~\-\.])|
+ (?[!$&\'()*+,;=:]) # also include the : character
+ )+
+ $/ix';
+
+ /**
+ * General registered name regular expression.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ private const REGEXP_REGISTERED_NAME = '/(?(DEFINE)
+ (?[a-z0-9_~\-]) # . is missing as it is used to separate labels
+ (?[!$&\'()*+,;=])
+ (?%[A-F0-9]{2})
+ (?(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*)
+ )
+ ^(?:(?®_name)\.)*(?®_name)\.?$/ix';
+
+ /**
+ * Invalid characters in host regular expression.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ */
+ private const REGEXP_INVALID_HOST_CHARS = '/
+ [:\/?#\[\]@ ] # gen-delims characters as well as the space character
+ /ix';
+
+ /**
+ * Invalid path for URI without scheme and authority regular expression.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.3
+ */
+ private const REGEXP_INVALID_PATH = ',^(([^/]*):)(.*)?/,';
+
+ /**
+ * Host and Port splitter regular expression.
+ */
+ private const REGEXP_HOST_PORT = ',^(?\[.*\]|[^:]*)(:(?.*))?$,';
+
+ /**
+ * IDN Host detector regular expression.
+ */
+ private const REGEXP_IDN_PATTERN = '/[^\x20-\x7f]/';
+
+ /**
+ * Only the address block fe80::/10 can have a Zone ID attach to
+ * let's detect the link local significant 10 bits.
+ */
+ private const ZONE_ID_ADDRESS_BLOCK = "\xfe\x80";
+
+ /**
+ * Generate an URI string representation from its parsed representation
+ * returned by League\UriString::parse() or PHP's parse_url.
+ *
+ * If you supply your own array, you are responsible for providing
+ * valid components without their URI delimiters.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5.3
+ * @link https://tools.ietf.org/html/rfc3986#section-7.5
+ *
+ * @param array{scheme:?string, user:?string, pass:?string, host:?string, port:?int, path:?string, query:?string, fragment:?string} $components
+ */
+ public static function build(array $components): string
+ {
+ $result = $components['path'] ?? '';
+ if (isset($components['query'])) {
+ $result .= '?'.$components['query'];
+ }
+
+ if (isset($components['fragment'])) {
+ $result .= '#'.$components['fragment'];
+ }
+
+ $scheme = null;
+ if (isset($components['scheme'])) {
+ $scheme = $components['scheme'].':';
+ }
+
+ if (!isset($components['host'])) {
+ return $scheme.$result;
+ }
+
+ $scheme .= '//';
+ $authority = $components['host'];
+ if (isset($components['port'])) {
+ $authority .= ':'.$components['port'];
+ }
+
+ if (!isset($components['user'])) {
+ return $scheme.$authority.$result;
+ }
+
+ $authority = '@'.$authority;
+ if (!isset($components['pass'])) {
+ return $scheme.$components['user'].$authority.$result;
+ }
+
+ return $scheme.$components['user'].':'.$components['pass'].$authority.$result;
+ }
+
+ /**
+ * Parse an URI string into its components.
+ *
+ * This method parses a URI and returns an associative array containing any
+ * of the various components of the URI that are present.
+ *
+ *
+ * $components = (new Parser())->parse('http://foo@test.example.com:42?query#');
+ * var_export($components);
+ * //will display
+ * array(
+ * 'scheme' => 'http', // the URI scheme component
+ * 'user' => 'foo', // the URI user component
+ * 'pass' => null, // the URI pass component
+ * 'host' => 'test.example.com', // the URI host component
+ * 'port' => 42, // the URI port component
+ * 'path' => '', // the URI path component
+ * 'query' => 'query', // the URI query component
+ * 'fragment' => '', // the URI fragment component
+ * );
+ *
+ *
+ * The returned array is similar to PHP's parse_url return value with the following
+ * differences:
+ *
+ *
+ *
All components are always present in the returned array
+ *
Empty and undefined component are treated differently. And empty component is
+ * set to the empty string while an undefined component is set to the `null` value.
+ *
The path component is never undefined
+ *
The method parses the URI following the RFC3986 rules but you are still
+ * required to validate the returned components against its related scheme specific rules.
+ *
+ *
+ * @link https://tools.ietf.org/html/rfc3986
+ *
+ * @param Stringable|string|int|float $uri any scalar or stringable object
+ *
+ * @throws SyntaxError if the URI contains invalid characters
+ * @throws SyntaxError if the URI contains an invalid scheme
+ * @throws SyntaxError if the URI contains an invalid path
+ *
+ * @return array{scheme:?string, user:?string, pass:?string, host:?string, port:?int, path:string, query:?string, fragment:?string}
+ */
+ public static function parse(Stringable|string|int|float $uri): array
+ {
+ $uri = (string) $uri;
+ if (isset(self::URI_SCHORTCUTS[$uri])) {
+ /** @var array{scheme:?string, user:?string, pass:?string, host:?string, port:?int, path:string, query:?string, fragment:?string} $components */
+ $components = array_merge(self::URI_COMPONENTS, self::URI_SCHORTCUTS[$uri]);
+
+ return $components;
+ }
+
+ if (1 === preg_match(self::REGEXP_INVALID_URI_CHARS, $uri)) {
+ throw new SyntaxError(sprintf('The uri `%s` contains invalid characters', $uri));
+ }
+
+ //if the first character is a known URI delimiter parsing can be simplified
+ $first_char = $uri[0];
+
+ //The URI is made of the fragment only
+ if ('#' === $first_char) {
+ [, $fragment] = explode('#', $uri, 2);
+ $components = self::URI_COMPONENTS;
+ $components['fragment'] = $fragment;
+
+ return $components;
+ }
+
+ //The URI is made of the query and fragment
+ if ('?' === $first_char) {
+ [, $partial] = explode('?', $uri, 2);
+ [$query, $fragment] = explode('#', $partial, 2) + [1 => null];
+ $components = self::URI_COMPONENTS;
+ $components['query'] = $query;
+ $components['fragment'] = $fragment;
+
+ return $components;
+ }
+
+ //use RFC3986 URI regexp to split the URI
+ preg_match(self::REGEXP_URI_PARTS, $uri, $parts);
+ $parts += ['query' => '', 'fragment' => ''];
+
+ if (':' === $parts['scheme'] || 1 !== preg_match(self::REGEXP_URI_SCHEME, $parts['scontent'])) {
+ throw new SyntaxError(sprintf('The uri `%s` contains an invalid scheme', $uri));
+ }
+
+ if ('' === $parts['scheme'].$parts['authority'] && 1 === preg_match(self::REGEXP_INVALID_PATH, $parts['path'])) {
+ throw new SyntaxError(sprintf('The uri `%s` contains an invalid path.', $uri));
+ }
+
+ /** @var array{scheme:?string, user:?string, pass:?string, host:?string, port:?int, path:string, query:?string, fragment:?string} $components */
+ $components = array_merge(
+ self::URI_COMPONENTS,
+ '' === $parts['authority'] ? [] : self::parseAuthority($parts['acontent']),
+ [
+ 'path' => $parts['path'],
+ 'scheme' => '' === $parts['scheme'] ? null : $parts['scontent'],
+ 'query' => '' === $parts['query'] ? null : $parts['qcontent'],
+ 'fragment' => '' === $parts['fragment'] ? null : $parts['fcontent'],
+ ]
+ );
+
+ return $components;
+ }
+
+ /**
+ * Parses the URI authority part.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2
+ *
+ * @throws SyntaxError If the port component is invalid
+ *
+ * @return array{user:?string, pass:?string, host:?string, port:?int}
+ */
+ private static function parseAuthority(string $authority): array
+ {
+ $components = ['user' => null, 'pass' => null, 'host' => '', 'port' => null];
+ if ('' === $authority) {
+ return $components;
+ }
+
+ $parts = explode('@', $authority, 2);
+ if (isset($parts[1])) {
+ [$components['user'], $components['pass']] = explode(':', $parts[0], 2) + [1 => null];
+ }
+
+ preg_match(self::REGEXP_HOST_PORT, $parts[1] ?? $parts[0], $matches);
+ $matches += ['port' => ''];
+
+ $components['port'] = self::filterPort($matches['port']);
+ $components['host'] = self::filterHost($matches['host']);
+
+ return $components;
+ }
+
+ /**
+ * Filter and format the port component.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ *
+ * @throws SyntaxError if the registered name is invalid
+ */
+ private static function filterPort(string $port): ?int
+ {
+ if ('' === $port) {
+ return null;
+ }
+
+ if (1 === preg_match('/^\d*$/', $port)) {
+ return (int) $port;
+ }
+
+ throw new SyntaxError(sprintf('The port `%s` is invalid', $port));
+ }
+
+ /**
+ * Returns whether a hostname is valid.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ *
+ * @throws SyntaxError if the registered name is invalid
+ */
+ private static function filterHost(string $host): string
+ {
+ if ('' === $host) {
+ return $host;
+ }
+
+ if ('[' !== $host[0] || !str_ends_with($host, ']')) {
+ return self::filterRegisteredName($host);
+ }
+
+ if (!self::isIpHost(substr($host, 1, -1))) {
+ throw new SyntaxError(sprintf('Host `%s` is invalid : the IP host is malformed', $host));
+ }
+
+ return $host;
+ }
+
+ /**
+ * Returns whether the host is an IPv4 or a registered named.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ *
+ * @throws SyntaxError if the registered name is invalid
+ * @throws IdnSupportMissing if IDN support or ICU requirement are not available or met.
+ */
+ private static function filterRegisteredName(string $host): string
+ {
+ $formatted_host = rawurldecode($host);
+ if (1 === preg_match(self::REGEXP_REGISTERED_NAME, $formatted_host)) {
+ return $host;
+ }
+
+ //to test IDN host non-ascii characters must be present in the host
+ if (1 !== preg_match(self::REGEXP_IDN_PATTERN, $formatted_host)) {
+ throw new SyntaxError(sprintf('Host `%s` is invalid : the host is not a valid registered name', $host));
+ }
+
+ $info = Idna::toAscii($host, Idna::IDNA2008_ASCII);
+ if (0 !== $info->errors()) {
+ throw IdnaConversionFailed::dueToIDNAError($host, $info);
+ }
+
+ return $host;
+ }
+
+ /**
+ * Validates a IPv6/IPvfuture host.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-3.2.2
+ * @link https://tools.ietf.org/html/rfc6874#section-2
+ * @link https://tools.ietf.org/html/rfc6874#section-4
+ */
+ private static function isIpHost(string $ip_host): bool
+ {
+ if (false !== filter_var($ip_host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ return true;
+ }
+
+ if (1 === preg_match(self::REGEXP_IP_FUTURE, $ip_host, $matches)) {
+ return !in_array($matches['version'], ['4', '6'], true);
+ }
+
+ $pos = strpos($ip_host, '%');
+ if (false === $pos || 1 === preg_match(
+ self::REGEXP_INVALID_HOST_CHARS,
+ rawurldecode(substr($ip_host, $pos))
+ )) {
+ return false;
+ }
+
+ $ip_host = substr($ip_host, 0, $pos);
+
+ return false !== filter_var($ip_host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)
+ && str_starts_with((string)inet_pton($ip_host), self::ZONE_ID_ADDRESS_BLOCK);
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriTemplate.php b/api_candidatos/vendor/league/uri/src/UriTemplate.php
new file mode 100644
index 0000000..3a9a333
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriTemplate.php
@@ -0,0 +1,131 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri;
+
+use League\Uri\Contracts\UriException;
+use League\Uri\Contracts\UriInterface;
+use League\Uri\Exceptions\SyntaxError;
+use League\Uri\Exceptions\TemplateCanNotBeExpanded;
+use League\Uri\UriTemplate\Template;
+use League\Uri\UriTemplate\VariableBag;
+use Stringable;
+
+/**
+ * Defines the URI Template syntax and the process for expanding a URI Template into a URI reference.
+ *
+ * @link https://tools.ietf.org/html/rfc6570
+ * @package League\Uri
+ * @author Ignace Nyamagana Butera
+ * @since 6.1.0
+ *
+ * Based on GuzzleHttp\UriTemplate class in Guzzle v6.5.
+ * @link https://github.com/guzzle/guzzle/blob/6.5/src/UriTemplate.php
+ */
+final class UriTemplate
+{
+ public readonly Template $template;
+ public readonly VariableBag $defaultVariables;
+
+ /**
+ * @throws SyntaxError if the template syntax is invalid
+ * @throws TemplateCanNotBeExpanded if the template variables are invalid
+ */
+ public function __construct(Template|Stringable|string $template, VariableBag|array $defaultVariables = [])
+ {
+ $this->template = $template instanceof Template ? $template : Template::createFromString($template);
+ $this->defaultVariables = $this->filterVariables($defaultVariables);
+ }
+
+ public static function __set_state(array $properties): self
+ {
+ return new self($properties['template'], $properties['defaultVariables']);
+ }
+
+ /**
+ * Filters out variables for the given template.
+ *
+ * @param array> $variables
+ */
+ private function filterVariables(VariableBag|array $variables): VariableBag
+ {
+ return array_reduce(
+ $this->template->variableNames,
+ function (VariableBag $curry, string $name) use ($variables): VariableBag {
+ if (isset($variables[$name])) {
+ $curry[$name] = $variables[$name];
+ }
+
+ return $curry;
+ },
+ new VariableBag()
+ );
+ }
+
+ /**
+ * The template string.
+ */
+ public function getTemplate(): string
+ {
+ return $this->template->value;
+ }
+
+ /**
+ * Returns the names of the variables in the template, in order.
+ *
+ * @return string[]
+ */
+ public function getVariableNames(): array
+ {
+ return $this->template->variableNames;
+ }
+
+ /**
+ * Returns the default values used to expand the template.
+ *
+ * The returned list only contains variables whose name is part of the current template.
+ *
+ * @return array
+ */
+ public function getDefaultVariables(): array
+ {
+ return $this->defaultVariables->all();
+ }
+
+ /**
+ * Returns a new instance with the updated default variables.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the modified default variables.
+ *
+ * If present, variables whose name is not part of the current template
+ * possible variable names are removed.
+ */
+ public function withDefaultVariables(VariableBag|array $defaultDefaultVariables): self
+ {
+ return new self($this->template, $defaultDefaultVariables);
+ }
+
+ /**
+ * @throws TemplateCanNotBeExpanded if the variable contains nested array values
+ * @throws UriException if the resulting expansion can not be converted to a UriInterface instance
+ */
+ public function expand(VariableBag|array $variables = []): UriInterface
+ {
+ return Uri::createFromString(
+ $this->template->expand(
+ $this->filterVariables($variables)->replace($this->defaultVariables)
+ )
+ );
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriTemplate/Expression.php b/api_candidatos/vendor/league/uri/src/UriTemplate/Expression.php
new file mode 100644
index 0000000..0f998f5
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriTemplate/Expression.php
@@ -0,0 +1,298 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\UriTemplate;
+
+use League\Uri\Exceptions\SyntaxError;
+use League\Uri\Exceptions\TemplateCanNotBeExpanded;
+use function array_filter;
+use function array_map;
+use function array_unique;
+use function explode;
+use function implode;
+use function preg_match;
+use function rawurlencode;
+use function str_replace;
+use function substr;
+
+final class Expression
+{
+ /**
+ * Expression regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc6570#section-2.2
+ */
+ private const REGEXP_EXPRESSION = '/^\{
+ (?:
+ (?[\.\/;\?&\=,\!@\|\+#])?
+ (?[^\}]*)
+ )
+ \}$/x';
+
+ /**
+ * Reserved Operator characters.
+ *
+ * @link https://tools.ietf.org/html/rfc6570#section-2.2
+ */
+ private const RESERVED_OPERATOR = '=,!@|';
+
+ /**
+ * Processing behavior according to the expression type operator.
+ *
+ * @link https://tools.ietf.org/html/rfc6570#appendix-A
+ */
+ private const OPERATOR_HASH_LOOKUP = [
+ '' => ['prefix' => '', 'joiner' => ',', 'query' => false],
+ '+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
+ '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
+ '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
+ '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
+ ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
+ '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
+ '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true],
+ ];
+
+ /** @var array */
+ private array $varSpecifiers;
+ private string $joiner;
+ /** @var array */
+ public readonly array $variableNames;
+ public readonly string $value;
+
+ private function __construct(private string $operator, VarSpecifier ...$varSpecifiers)
+ {
+ $this->varSpecifiers = $varSpecifiers;
+ $this->joiner = self::OPERATOR_HASH_LOOKUP[$operator]['joiner'];
+ $this->variableNames = array_unique(array_map(
+ static fn (VarSpecifier $varSpecifier): string => $varSpecifier->name,
+ $varSpecifiers
+ ));
+ $this->value = '{'.$operator.implode(',', array_map(
+ static fn (VarSpecifier $varSpecifier): string => $varSpecifier->toString(),
+ $varSpecifiers
+ )).'}';
+ }
+
+ /**
+ * @param array{operator:string, varSpecifiers:array} $properties
+ */
+ public static function __set_state(array $properties): self
+ {
+ return new self($properties['operator'], ...$properties['varSpecifiers']);
+ }
+
+ /**
+ * @throws SyntaxError if the expression is invalid
+ * @throws SyntaxError if the operator used in the expression is invalid
+ * @throws SyntaxError if the variable specifiers is invalid
+ */
+ public static function createFromString(string $expression): self
+ {
+ if (1 !== preg_match(self::REGEXP_EXPRESSION, $expression, $parts)) {
+ throw new SyntaxError('The expression "'.$expression.'" is invalid.');
+ }
+
+ /** @var array{operator:string, variables:string} $parts */
+ $parts = $parts + ['operator' => ''];
+ if ('' !== $parts['operator'] && str_contains(self::RESERVED_OPERATOR, $parts['operator'])) {
+ throw new SyntaxError('The operator used in the expression "'.$expression.'" is reserved.');
+ }
+
+ return new Expression($parts['operator'], ...array_map(
+ static fn (string $varSpec): VarSpecifier => VarSpecifier::createFromString($varSpec),
+ explode(',', $parts['variables'])
+ ));
+ }
+
+ /**
+ * Returns the expression string representation.
+ *
+ * @deprecated since version 6.6.0 use the readonly property instead
+ * @codeCoverageIgnore
+ */
+ public function toString(): string
+ {
+ return $this->value;
+ }
+
+ /**
+ * @deprecated since version 6.6.0 use the readonly property instead
+ * @codeCoverageIgnore
+ *
+ * @return array
+ */
+ public function variableNames(): array
+ {
+ return $this->variableNames;
+ }
+
+ public function expand(VariableBag $variables): string
+ {
+ $parts = [];
+ foreach ($this->varSpecifiers as $varSpecifier) {
+ $parts[] = $this->replace($varSpecifier, $variables);
+ }
+
+ $expanded = implode($this->joiner, array_filter($parts, static fn ($value): bool => '' !== $value));
+ if ('' === $expanded) {
+ return $expanded;
+ }
+
+ $prefix = self::OPERATOR_HASH_LOOKUP[$this->operator]['prefix'];
+ if ('' === $prefix) {
+ return $expanded;
+ }
+
+ return $prefix.$expanded;
+ }
+
+ /**
+ * Replaces an expression with the given variables.
+ *
+ * @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
+ * @throws TemplateCanNotBeExpanded if the variables contains nested array values
+ */
+ private function replace(VarSpecifier $varSpec, VariableBag $variables): string
+ {
+ $value = $variables->fetch($varSpec->name);
+ if (null === $value) {
+ return '';
+ }
+
+ $useQuery = self::OPERATOR_HASH_LOOKUP[$this->operator]['query'];
+ [$expanded, $actualQuery] = $this->inject($value, $varSpec, $useQuery);
+ if (!$actualQuery) {
+ return $expanded;
+ }
+
+ if ('&' !== $this->joiner && '' === $expanded) {
+ return $varSpec->name;
+ }
+
+ return $varSpec->name.'='.$expanded;
+ }
+
+ /**
+ * @param string|array $value
+ *
+ * @return array{0:string, 1:bool}
+ */
+ private function inject(array|string $value, VarSpecifier $varSpec, bool $useQuery): array
+ {
+ if (is_string($value)) {
+ return $this->replaceString($value, $varSpec, $useQuery);
+ }
+
+ return $this->replaceList($value, $varSpec, $useQuery);
+ }
+
+ /**
+ * Expands an expression using a string value.
+ *
+ * @return array{0:string, 1:bool}
+ */
+ private function replaceString(string $value, VarSpecifier $varSpec, bool $useQuery): array
+ {
+ if (':' === $varSpec->modifier) {
+ $value = substr($value, 0, $varSpec->position);
+ }
+
+ if (in_array($this->operator, ['+', '#'], true)) {
+ return [$this->decodeReserved(rawurlencode($value)), $useQuery];
+ }
+
+ return [rawurlencode($value), $useQuery];
+ }
+
+ /**
+ * Expands an expression using a list of values.
+ *
+ * @param array $value
+ *
+ * @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
+ *
+ * @return array{0:string, 1:bool}
+ */
+ private function replaceList(array $value, VarSpecifier $varSpec, bool $useQuery): array
+ {
+ if ([] === $value) {
+ return ['', false];
+ }
+
+ if (':' === $varSpec->modifier) {
+ throw TemplateCanNotBeExpanded::dueToUnableToProcessValueListWithPrefix($varSpec->name);
+ }
+
+ $pairs = [];
+ $isList = array_is_list($value);
+ foreach ($value as $key => $var) {
+ if (!$isList) {
+ $key = rawurlencode((string) $key);
+ }
+
+ $var = rawurlencode($var);
+ if (in_array($this->operator, ['+', '#'], true)) {
+ $var = $this->decodeReserved($var);
+ }
+
+ if ('*' === $varSpec->modifier) {
+ if (!$isList) {
+ $var = $key.'='.$var;
+ } elseif ($key > 0 && $useQuery) {
+ $var = $varSpec->name.'='.$var;
+ }
+ }
+
+ $pairs[$key] = $var;
+ }
+
+ if ('*' === $varSpec->modifier) {
+ if (!$isList) {
+ // Don't prepend the value name when using the `explode` modifier with an associative array.
+ $useQuery = false;
+ }
+
+ return [implode($this->joiner, $pairs), $useQuery];
+ }
+
+ if (!$isList) {
+ // When an associative array is encountered and the `explode` modifier is not set, then
+ // the result must be a comma separated list of keys followed by their respective values.
+ foreach ($pairs as $offset => &$data) {
+ $data = $offset.','.$data;
+ }
+
+ unset($data);
+ }
+
+ return [implode(',', $pairs), $useQuery];
+ }
+
+ /**
+ * Removes percent encoding on reserved characters (used with + and # modifiers).
+ */
+ private function decodeReserved(string $str): string
+ {
+ static $delimiters = [
+ ':', '/', '?', '#', '[', ']', '@', '!', '$',
+ '&', '\'', '(', ')', '*', '+', ',', ';', '=',
+ ];
+
+ static $delimitersEncoded = [
+ '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24',
+ '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D',
+ ];
+
+ return str_replace($delimitersEncoded, $delimiters, $str);
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriTemplate/Template.php b/api_candidatos/vendor/league/uri/src/UriTemplate/Template.php
new file mode 100644
index 0000000..826bcbc
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriTemplate/Template.php
@@ -0,0 +1,116 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\UriTemplate;
+
+use League\Uri\Exceptions\SyntaxError;
+use League\Uri\Exceptions\TemplateCanNotBeExpanded;
+use Stringable;
+use function array_unique;
+use function preg_match_all;
+use function preg_replace;
+use function str_contains;
+use const PREG_SET_ORDER;
+
+final class Template
+{
+ /**
+ * Expression regular expression pattern.
+ */
+ private const REGEXP_EXPRESSION_DETECTOR = '/\{[^}]*}/x';
+
+ /** @var array */
+ private array $expressions = [];
+ /** @var array */
+ public readonly array $variableNames;
+
+ private function __construct(public readonly string $value, Expression ...$expressions)
+ {
+ $variableNames = [];
+ foreach ($expressions as $expression) {
+ $this->expressions[$expression->value] = $expression;
+ $variableNames = [...$variableNames, ...$expression->variableNames];
+ }
+
+ $this->variableNames = array_unique($variableNames);
+ }
+
+ /**
+ * @param array{value:string, template?:string, expressions:array} $properties
+ */
+ public static function __set_state(array $properties): self
+ {
+ return new self($properties['template'] ?? $properties['value'], ...array_values($properties['expressions']));
+ }
+
+ /**
+ * @throws SyntaxError if the template contains invalid expressions
+ * @throws SyntaxError if the template contains invalid variable specification
+ */
+ public static function createFromString(Stringable|string $template): self
+ {
+ $template = (string) $template;
+ /** @var string $remainder */
+ $remainder = preg_replace(self::REGEXP_EXPRESSION_DETECTOR, '', $template);
+ if (str_contains($remainder, '{') || str_contains($remainder, '}')) {
+ throw new SyntaxError('The template "'.$template.'" contains invalid expressions.');
+ }
+
+ $names = [];
+ preg_match_all(self::REGEXP_EXPRESSION_DETECTOR, $template, $findings, PREG_SET_ORDER);
+ $arguments = [];
+ foreach ($findings as $finding) {
+ if (!isset($names[$finding[0]])) {
+ $arguments[] = Expression::createFromString($finding[0]);
+ $names[$finding[0]] = 1;
+ }
+ }
+
+ return new self($template, ...$arguments);
+ }
+
+ /**
+ * @deprecated since version 6.6.0 use the readonly property instead
+ * @codeCoverageIgnore
+ */
+ public function toString(): string
+ {
+ return $this->value;
+ }
+
+ /**
+ * @deprecated since version 6.6.0 use the readonly property instead
+ * @codeCoverageIgnore
+ *
+ * @return array
+ */
+ public function variableNames(): array
+ {
+ return $this->variableNames;
+ }
+
+ /**
+ * @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
+ * @throws TemplateCanNotBeExpanded if the variables contains nested array values
+ */
+ public function expand(VariableBag $variables): string
+ {
+ $uriString = $this->value;
+ /** @var Expression $expression */
+ foreach ($this->expressions as $pattern => $expression) {
+ $uriString = str_replace($pattern, $expression->expand($variables), $uriString);
+ }
+
+ return $uriString;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriTemplate/VarSpecifier.php b/api_candidatos/vendor/league/uri/src/UriTemplate/VarSpecifier.php
new file mode 100644
index 0000000..0827a0a
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriTemplate/VarSpecifier.php
@@ -0,0 +1,104 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\UriTemplate;
+
+use League\Uri\Exceptions\SyntaxError;
+use function preg_match;
+
+final class VarSpecifier
+{
+ /**
+ * Variables specification regular expression pattern.
+ *
+ * @link https://tools.ietf.org/html/rfc6570#section-2.3
+ */
+ private const REGEXP_VARSPEC = '/^
+ (?(?:[A-z0-9_\.]|%[0-9a-fA-F]{2})+)
+ (?\:(?\d+)|\*)?
+ $/x';
+
+ private function __construct(
+ public readonly string $name,
+ public readonly string $modifier,
+ public readonly int $position
+ ) {
+ }
+
+ /**
+ * @param array{name: string, modifier:string, position:int} $properties
+ */
+ public static function __set_state(array $properties): self
+ {
+ return new self($properties['name'], $properties['modifier'], $properties['position']);
+ }
+
+ public static function createFromString(string $specification): self
+ {
+ if (1 !== preg_match(self::REGEXP_VARSPEC, $specification, $parsed)) {
+ throw new SyntaxError('The variable specification "'.$specification.'" is invalid.');
+ }
+
+ $parsed += ['modifier' => '', 'position' => ''];
+ if ('' !== $parsed['position']) {
+ $parsed['position'] = (int) $parsed['position'];
+ $parsed['modifier'] = ':';
+ }
+
+ if ('' === $parsed['position']) {
+ $parsed['position'] = 0;
+ }
+
+ if (10000 <= $parsed['position']) {
+ throw new SyntaxError('The variable specification "'.$specification.'" is invalid the position modifier must be lower than 10000.');
+ }
+
+ return new self($parsed['name'], $parsed['modifier'], $parsed['position']);
+ }
+
+ public function toString(): string
+ {
+ if (0 < $this->position) {
+ return $this->name.$this->modifier.$this->position;
+ }
+
+ return $this->name.$this->modifier;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated since version 6.6.0 use the readonly property instead
+ */
+ public function name(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated since version 6.6.0 use the readonly property instead
+ */
+ public function modifier(): string
+ {
+ return $this->modifier;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated since version 6.6.0 use the readonly property instead
+ */
+ public function position(): int
+ {
+ return $this->position;
+ }
+}
diff --git a/api_candidatos/vendor/league/uri/src/UriTemplate/VariableBag.php b/api_candidatos/vendor/league/uri/src/UriTemplate/VariableBag.php
new file mode 100644
index 0000000..a3e559d
--- /dev/null
+++ b/api_candidatos/vendor/league/uri/src/UriTemplate/VariableBag.php
@@ -0,0 +1,133 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Uri\UriTemplate;
+
+use ArrayAccess;
+use Countable;
+use League\Uri\Exceptions\TemplateCanNotBeExpanded;
+use Stringable;
+use function is_bool;
+use function is_object;
+use function is_scalar;
+
+/**
+ * @implements ArrayAccess>
+ */
+final class VariableBag implements ArrayAccess, Countable
+{
+ /**
+ * @var array>
+ */
+ private array $variables = [];
+
+ /**
+ * @param iterable> $variables
+ */
+ public function __construct(iterable $variables = [])
+ {
+ foreach ($variables as $name => $value) {
+ $this->assign($name, $value);
+ }
+ }
+
+ public function count(): int
+ {
+ return count($this->variables);
+ }
+
+ /**
+ * @param array{variables: array>} $properties
+ */
+ public static function __set_state(array $properties): self
+ {
+ return new self($properties['variables']);
+ }
+
+ public function offsetExists(mixed $offset): bool
+ {
+ return array_key_exists($offset, $this->variables);
+ }
+
+ public function offsetUnset(mixed $offset): void
+ {
+ unset($this->variables[$offset]);
+ }
+
+ public function offsetSet(mixed $offset, mixed $value): void
+ {
+ $this->assign($offset, $value); /* @phpstan-ignore-line */
+ }
+
+ public function offsetGet(mixed $offset): mixed
+ {
+ return $this->fetch($offset);
+ }
+
+ /**
+ * @return array>
+ */
+ public function all(): array
+ {
+ return $this->variables;
+ }
+
+ /**
+ * Tells whether the bag is empty or not.
+ */
+ public function isEmpty(): bool
+ {
+ return [] === $this->variables;
+ }
+
+ /**
+ * Fetches the variable value if none found returns null.
+ *
+ * @return null|string|array
+ */
+ public function fetch(string $name): null|string|array
+ {
+ return $this->variables[$name] ?? null;
+ }
+
+ /**
+ * @param string|bool|int|float|null|array $value
+ */
+ public function assign(string $name, string|bool|int|float|array|null $value): void
+ {
+ $this->variables[$name] = $this->normalizeValue($value, $name, true);
+ }
+
+ /**
+ * @param Stringable|string|float|int|bool|null $value the value to be expanded
+ *
+ * @throws TemplateCanNotBeExpanded if the value contains nested list
+ */
+ private function normalizeValue(Stringable|array|string|float|int|bool|null $value, string $name, bool $isNestedListAllowed): array|string
+ {
+ return match (true) {
+ is_bool($value) => true === $value ? '1' : '0',
+ (null === $value || is_scalar($value) || is_object($value)) => (string) $value,
+ !$isNestedListAllowed => throw TemplateCanNotBeExpanded::dueToNestedListOfValue($name),
+ default => array_map(fn ($var): array|string => self::normalizeValue($var, $name, false), $value),
+ };
+ }
+
+ /**
+ * Replaces elements from passed variables into the current instance.
+ */
+ public function replace(VariableBag $variables): self
+ {
+ return new self($this->variables + $variables->variables);
+ }
+}
diff --git a/api_candidatos/vendor/paragonie/random_compat/LICENSE b/api_candidatos/vendor/paragonie/random_compat/LICENSE
new file mode 100644
index 0000000..45c7017
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Paragon Initiative Enterprises
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/api_candidatos/vendor/paragonie/random_compat/build-phar.sh b/api_candidatos/vendor/paragonie/random_compat/build-phar.sh
new file mode 100644
index 0000000..b4a5ba3
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/build-phar.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) )
+
+php -dphar.readonly=0 "$basedir/other/build_phar.php" $*
\ No newline at end of file
diff --git a/api_candidatos/vendor/paragonie/random_compat/composer.json b/api_candidatos/vendor/paragonie/random_compat/composer.json
new file mode 100644
index 0000000..f2b9c4e
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "paragonie/random_compat",
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "random",
+ "polyfill",
+ "pseudorandom"
+ ],
+ "license": "MIT",
+ "type": "library",
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "support": {
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "email": "info@paragonie.com",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "vimeo/psalm": "^1",
+ "phpunit/phpunit": "4.*|5.*"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ }
+}
diff --git a/api_candidatos/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/api_candidatos/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey
new file mode 100644
index 0000000..eb50ebf
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
+pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
+-----END PUBLIC KEY-----
diff --git a/api_candidatos/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/api_candidatos/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc
new file mode 100644
index 0000000..6a1d7f3
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2.0.22 (MingW32)
+
+iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
+QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
+1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
+NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
+NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
+JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
+=B6+8
+-----END PGP SIGNATURE-----
diff --git a/api_candidatos/vendor/paragonie/random_compat/lib/random.php b/api_candidatos/vendor/paragonie/random_compat/lib/random.php
new file mode 100644
index 0000000..c7731a5
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/lib/random.php
@@ -0,0 +1,32 @@
+buildFromDirectory(dirname(__DIR__).'/lib');
+rename(
+ dirname(__DIR__).'/lib/index.php',
+ dirname(__DIR__).'/lib/random.php'
+);
+
+/**
+ * If we pass an (optional) path to a private key as a second argument, we will
+ * sign the Phar with OpenSSL.
+ *
+ * If you leave this out, it will produce an unsigned .phar!
+ */
+if ($argc > 1) {
+ if (!@is_readable($argv[1])) {
+ echo 'Could not read the private key file:', $argv[1], "\n";
+ exit(255);
+ }
+ $pkeyFile = file_get_contents($argv[1]);
+
+ $private = openssl_get_privatekey($pkeyFile);
+ if ($private !== false) {
+ $pkey = '';
+ openssl_pkey_export($private, $pkey);
+ $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);
+
+ /**
+ * Save the corresponding public key to the file
+ */
+ if (!@is_readable($dist.'/random_compat.phar.pubkey')) {
+ $details = openssl_pkey_get_details($private);
+ file_put_contents(
+ $dist.'/random_compat.phar.pubkey',
+ $details['key']
+ );
+ }
+ } else {
+ echo 'An error occurred reading the private key from OpenSSL.', "\n";
+ exit(255);
+ }
+}
diff --git a/api_candidatos/vendor/paragonie/random_compat/psalm-autoload.php b/api_candidatos/vendor/paragonie/random_compat/psalm-autoload.php
new file mode 100644
index 0000000..d71d1b8
--- /dev/null
+++ b/api_candidatos/vendor/paragonie/random_compat/psalm-autoload.php
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api_candidatos/vendor/psr/clock/CHANGELOG.md b/api_candidatos/vendor/psr/clock/CHANGELOG.md
new file mode 100644
index 0000000..3cd6b9b
--- /dev/null
+++ b/api_candidatos/vendor/psr/clock/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Changelog
+
+All notable changes to this project will be documented in this file, in reverse chronological order by release.
+
+## 1.0.0
+
+First stable release after PSR-20 acceptance
+
+## 0.1.0
+
+First release
diff --git a/api_candidatos/vendor/psr/clock/LICENSE b/api_candidatos/vendor/psr/clock/LICENSE
new file mode 100644
index 0000000..be68342
--- /dev/null
+++ b/api_candidatos/vendor/psr/clock/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2017 PHP Framework Interoperability Group
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/api_candidatos/vendor/psr/clock/README.md b/api_candidatos/vendor/psr/clock/README.md
new file mode 100644
index 0000000..6ca877e
--- /dev/null
+++ b/api_candidatos/vendor/psr/clock/README.md
@@ -0,0 +1,61 @@
+# PSR Clock
+
+This repository holds the interface for [PSR-20][psr-url].
+
+Note that this is not a clock of its own. It is merely an interface that
+describes a clock. See the specification for more details.
+
+## Installation
+
+```bash
+composer require psr/clock
+```
+
+## Usage
+
+If you need a clock, you can use the interface like this:
+
+```php
+clock = $clock;
+ }
+
+ public function doSomething()
+ {
+ /** @var DateTimeImmutable $currentDateAndTime */
+ $currentDateAndTime = $this->clock->now();
+ // do something useful with that information
+ }
+}
+```
+
+You can then pick one of the [implementations][implementation-url] of the interface to get a clock.
+
+If you want to implement the interface, you can require this package and
+implement `Psr\Clock\ClockInterface` in your code.
+
+Don't forget to add `psr/clock-implementation` to your `composer.json`s `provides`-section like this:
+
+```json
+{
+ "provides": {
+ "psr/clock-implementation": "1.0"
+ }
+}
+```
+
+And please read the [specification text][specification-url] for details on the interface.
+
+[psr-url]: https://www.php-fig.org/psr/psr-20
+[package-url]: https://packagist.org/packages/psr/clock
+[implementation-url]: https://packagist.org/providers/psr/clock-implementation
+[specification-url]: https://github.com/php-fig/fig-standards/blob/master/proposed/clock.md
diff --git a/api_candidatos/vendor/psr/clock/composer.json b/api_candidatos/vendor/psr/clock/composer.json
new file mode 100644
index 0000000..77992ed
--- /dev/null
+++ b/api_candidatos/vendor/psr/clock/composer.json
@@ -0,0 +1,21 @@
+{
+ "name": "psr/clock",
+ "description": "Common interface for reading the clock.",
+ "keywords": ["psr", "psr-20", "time", "clock", "now"],
+ "homepage": "https://github.com/php-fig/clock",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/psr/clock/src/ClockInterface.php b/api_candidatos/vendor/psr/clock/src/ClockInterface.php
new file mode 100644
index 0000000..7b6d8d8
--- /dev/null
+++ b/api_candidatos/vendor/psr/clock/src/ClockInterface.php
@@ -0,0 +1,13 @@
+=7.1",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/psr/http-factory/src/RequestFactoryInterface.php b/api_candidatos/vendor/psr/http-factory/src/RequestFactoryInterface.php
new file mode 100644
index 0000000..cb39a08
--- /dev/null
+++ b/api_candidatos/vendor/psr/http-factory/src/RequestFactoryInterface.php
@@ -0,0 +1,18 @@
+ `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`.
+> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered.
+
diff --git a/api_candidatos/vendor/psr/http-message/docs/PSR7-Usage.md b/api_candidatos/vendor/psr/http-message/docs/PSR7-Usage.md
new file mode 100644
index 0000000..b6d048a
--- /dev/null
+++ b/api_candidatos/vendor/psr/http-message/docs/PSR7-Usage.md
@@ -0,0 +1,159 @@
+### PSR-7 Usage
+
+All PSR-7 applications comply with these interfaces
+They were created to establish a standard between middleware implementations.
+
+> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`.
+> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered.
+
+
+The following examples will illustrate how basic operations are done in PSR-7.
+
+##### Examples
+
+
+For this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc)
+All PSR-7 implementations should have the same behaviour.
+
+The following will be assumed:
+`$request` is an object of `Psr\Http\Message\RequestInterface` and
+
+`$response` is an object implementing `Psr\Http\Message\RequestInterface`
+
+
+### Working with HTTP Headers
+
+#### Adding headers to response:
+
+```php
+$response->withHeader('My-Custom-Header', 'My Custom Message');
+```
+
+#### Appending values to headers
+
+```php
+$response->withAddedHeader('My-Custom-Header', 'The second message');
+```
+
+#### Checking if header exists:
+
+```php
+$request->hasHeader('My-Custom-Header'); // will return false
+$response->hasHeader('My-Custom-Header'); // will return true
+```
+
+> Note: My-Custom-Header was only added in the Response
+
+#### Getting comma-separated values from a header (also applies to request)
+
+```php
+// getting value from request headers
+$request->getHeaderLine('Content-Type'); // will return: "text/html; charset=UTF-8"
+// getting value from response headers
+$response->getHeaderLine('My-Custom-Header'); // will return: "My Custom Message; The second message"
+```
+
+#### Getting array of value from a header (also applies to request)
+```php
+// getting value from request headers
+$request->getHeader('Content-Type'); // will return: ["text/html", "charset=UTF-8"]
+// getting value from response headers
+$response->getHeader('My-Custom-Header'); // will return: ["My Custom Message", "The second message"]
+```
+
+#### Removing headers from HTTP Messages
+```php
+// removing a header from Request, removing deprecated "Content-MD5" header
+$request->withoutHeader('Content-MD5');
+
+// removing a header from Response
+// effect: the browser won't know the size of the stream
+// the browser will download the stream till it ends
+$response->withoutHeader('Content-Length');
+```
+
+### Working with HTTP Message Body
+
+When working with the PSR-7 there are two methods of implementation:
+#### 1. Getting the body separately
+
+> This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented.
+
+```php
+$body = $response->getBody();
+// operations on body, eg. read, write, seek
+// ...
+// replacing the old body
+$response->withBody($body);
+// this last statement is optional as we working with objects
+// in this case the "new" body is same with the "old" one
+// the $body variable has the same value as the one in $request, only the reference is passed
+```
+
+#### 2. Working directly on response
+
+> This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required
+
+```php
+$response->getBody()->write('hello');
+```
+
+### Getting the body contents
+
+The following snippet gets the contents of a stream contents.
+> Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\0` - meaning end of stream.
+```php
+$body = $response->getBody();
+$body->rewind(); // or $body->seek(0);
+$bodyText = $body->getContents();
+```
+> Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended.
+
+### Append to body
+
+```php
+$response->getBody()->write('Hello'); // writing directly
+$body = $request->getBody(); // which is a `StreamInterface`
+$body->write('xxxxx');
+```
+
+### Prepend to body
+Prepending is different when it comes to streams. The content must be copied before writing the content to be prepended.
+The following example will explain the behaviour of streams.
+
+```php
+// assuming our response is initially empty
+$body = $repsonse->getBody();
+// writing the string "abcd"
+$body->write('abcd');
+
+// seeking to start of stream
+$body->seek(0);
+// writing 'ef'
+$body->write('ef'); // at this point the stream contains "efcd"
+```
+
+#### Prepending by rewriting separately
+
+```php
+// assuming our response body stream only contains: "abcd"
+$body = $response->getBody();
+$body->rewind();
+$contents = $body->getContents(); // abcd
+// seeking the stream to beginning
+$body->rewind();
+$body->write('ef'); // stream contains "efcd"
+$body->write($contents); // stream contains "efabcd"
+```
+
+> Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`.
+
+#### Prepending by using contents as a string
+```php
+$body = $response->getBody();
+$body->rewind();
+$contents = $body->getContents(); // efabcd
+$contents = 'ef'.$contents;
+$body->rewind();
+$body->write($contents);
+```
diff --git a/api_candidatos/vendor/psr/http-message/src/MessageInterface.php b/api_candidatos/vendor/psr/http-message/src/MessageInterface.php
new file mode 100644
index 0000000..8cdb4ed
--- /dev/null
+++ b/api_candidatos/vendor/psr/http-message/src/MessageInterface.php
@@ -0,0 +1,189 @@
+getHeaders() as $name => $values) {
+ * echo $name . ": " . implode(", ", $values);
+ * }
+ *
+ * // Emit headers iteratively:
+ * foreach ($message->getHeaders() as $name => $values) {
+ * foreach ($values as $value) {
+ * header(sprintf('%s: %s', $name, $value), false);
+ * }
+ * }
+ *
+ * While header names are not case-sensitive, getHeaders() will preserve the
+ * exact case in which headers were originally specified.
+ *
+ * @return string[][] Returns an associative array of the message's headers. Each
+ * key MUST be a header name, and each value MUST be an array of strings
+ * for that header.
+ */
+ public function getHeaders();
+
+ /**
+ * Checks if a header exists by the given case-insensitive name.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return bool Returns true if any header names match the given header
+ * name using a case-insensitive string comparison. Returns false if
+ * no matching header name is found in the message.
+ */
+ public function hasHeader(string $name);
+
+ /**
+ * Retrieves a message header value by the given case-insensitive name.
+ *
+ * This method returns an array of all the header values of the given
+ * case-insensitive header name.
+ *
+ * If the header does not appear in the message, this method MUST return an
+ * empty array.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string[] An array of string values as provided for the given
+ * header. If the header does not appear in the message, this method MUST
+ * return an empty array.
+ */
+ public function getHeader(string $name);
+
+ /**
+ * Retrieves a comma-separated string of the values for a single header.
+ *
+ * This method returns all of the header values of the given
+ * case-insensitive header name as a string concatenated together using
+ * a comma.
+ *
+ * NOTE: Not all header values may be appropriately represented using
+ * comma concatenation. For such headers, use getHeader() instead
+ * and supply your own delimiter when concatenating.
+ *
+ * If the header does not appear in the message, this method MUST return
+ * an empty string.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string A string of values as provided for the given header
+ * concatenated together using a comma. If the header does not appear in
+ * the message, this method MUST return an empty string.
+ */
+ public function getHeaderLine(string $name);
+
+ /**
+ * Return an instance with the provided value replacing the specified header.
+ *
+ * While header names are case-insensitive, the casing of the header will
+ * be preserved by this function, and returned from getHeaders().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new and/or updated header and value.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @param string|string[] $value Header value(s).
+ * @return static
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withHeader(string $name, $value);
+
+ /**
+ * Return an instance with the specified header appended with the given value.
+ *
+ * Existing values for the specified header will be maintained. The new
+ * value(s) will be appended to the existing list. If the header did not
+ * exist previously, it will be added.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new header and/or value.
+ *
+ * @param string $name Case-insensitive header field name to add.
+ * @param string|string[] $value Header value(s).
+ * @return static
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withAddedHeader(string $name, $value);
+
+ /**
+ * Return an instance without the specified header.
+ *
+ * Header resolution MUST be done without case-sensitivity.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the named header.
+ *
+ * @param string $name Case-insensitive header field name to remove.
+ * @return static
+ */
+ public function withoutHeader(string $name);
+
+ /**
+ * Gets the body of the message.
+ *
+ * @return StreamInterface Returns the body as a stream.
+ */
+ public function getBody();
+
+ /**
+ * Return an instance with the specified message body.
+ *
+ * The body MUST be a StreamInterface object.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return a new instance that has the
+ * new body stream.
+ *
+ * @param StreamInterface $body Body.
+ * @return static
+ * @throws \InvalidArgumentException When the body is not valid.
+ */
+ public function withBody(StreamInterface $body);
+}
diff --git a/api_candidatos/vendor/psr/http-message/src/RequestInterface.php b/api_candidatos/vendor/psr/http-message/src/RequestInterface.php
new file mode 100644
index 0000000..38066df
--- /dev/null
+++ b/api_candidatos/vendor/psr/http-message/src/RequestInterface.php
@@ -0,0 +1,131 @@
+getQuery()`
+ * or from the `QUERY_STRING` server param.
+ *
+ * @return array
+ */
+ public function getQueryParams();
+
+ /**
+ * Return an instance with the specified query string arguments.
+ *
+ * These values SHOULD remain immutable over the course of the incoming
+ * request. They MAY be injected during instantiation, such as from PHP's
+ * $_GET superglobal, or MAY be derived from some other value such as the
+ * URI. In cases where the arguments are parsed from the URI, the data
+ * MUST be compatible with what PHP's parse_str() would return for
+ * purposes of how duplicate query parameters are handled, and how nested
+ * sets are handled.
+ *
+ * Setting query string arguments MUST NOT change the URI stored by the
+ * request, nor the values in the server params.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated query string arguments.
+ *
+ * @param array $query Array of query string arguments, typically from
+ * $_GET.
+ * @return static
+ */
+ public function withQueryParams(array $query);
+
+ /**
+ * Retrieve normalized file upload data.
+ *
+ * This method returns upload metadata in a normalized tree, with each leaf
+ * an instance of Psr\Http\Message\UploadedFileInterface.
+ *
+ * These values MAY be prepared from $_FILES or the message body during
+ * instantiation, or MAY be injected via withUploadedFiles().
+ *
+ * @return array An array tree of UploadedFileInterface instances; an empty
+ * array MUST be returned if no data is present.
+ */
+ public function getUploadedFiles();
+
+ /**
+ * Create a new instance with the specified uploaded files.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
+ * @return static
+ * @throws \InvalidArgumentException if an invalid structure is provided.
+ */
+ public function withUploadedFiles(array $uploadedFiles);
+
+ /**
+ * Retrieve any parameters provided in the request body.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, this method MUST
+ * return the contents of $_POST.
+ *
+ * Otherwise, this method may return any results of deserializing
+ * the request body content; as parsing returns structured content, the
+ * potential types MUST be arrays or objects only. A null value indicates
+ * the absence of body content.
+ *
+ * @return null|array|object The deserialized body parameters, if any.
+ * These will typically be an array or object.
+ */
+ public function getParsedBody();
+
+ /**
+ * Return an instance with the specified body parameters.
+ *
+ * These MAY be injected during instantiation.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, use this method
+ * ONLY to inject the contents of $_POST.
+ *
+ * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
+ * deserializing the request body content. Deserialization/parsing returns
+ * structured data, and, as such, this method ONLY accepts arrays or objects,
+ * or a null value if nothing was available to parse.
+ *
+ * As an example, if content negotiation determines that the request data
+ * is a JSON payload, this method could be used to create a request
+ * instance with the deserialized parameters.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param null|array|object $data The deserialized body data. This will
+ * typically be in an array or object.
+ * @return static
+ * @throws \InvalidArgumentException if an unsupported argument type is
+ * provided.
+ */
+ public function withParsedBody($data);
+
+ /**
+ * Retrieve attributes derived from the request.
+ *
+ * The request "attributes" may be used to allow injection of any
+ * parameters derived from the request: e.g., the results of path
+ * match operations; the results of decrypting cookies; the results of
+ * deserializing non-form-encoded message bodies; etc. Attributes
+ * will be application and request specific, and CAN be mutable.
+ *
+ * @return array Attributes derived from the request.
+ */
+ public function getAttributes();
+
+ /**
+ * Retrieve a single derived request attribute.
+ *
+ * Retrieves a single derived request attribute as described in
+ * getAttributes(). If the attribute has not been previously set, returns
+ * the default value as provided.
+ *
+ * This method obviates the need for a hasAttribute() method, as it allows
+ * specifying a default value to return if the attribute is not found.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $default Default value to return if the attribute does not exist.
+ * @return mixed
+ */
+ public function getAttribute(string $name, $default = null);
+
+ /**
+ * Return an instance with the specified derived request attribute.
+ *
+ * This method allows setting a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $value The value of the attribute.
+ * @return static
+ */
+ public function withAttribute(string $name, $value);
+
+ /**
+ * Return an instance that removes the specified derived request attribute.
+ *
+ * This method allows removing a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @return static
+ */
+ public function withoutAttribute(string $name);
+}
diff --git a/api_candidatos/vendor/psr/http-message/src/StreamInterface.php b/api_candidatos/vendor/psr/http-message/src/StreamInterface.php
new file mode 100644
index 0000000..5924663
--- /dev/null
+++ b/api_candidatos/vendor/psr/http-message/src/StreamInterface.php
@@ -0,0 +1,160 @@
+
+ * [user-info@]host[:port]
+ *
+ *
+ * If the port component is not set or is the standard port for the current
+ * scheme, it SHOULD NOT be included.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2
+ * @return string The URI authority, in "[user-info@]host[:port]" format.
+ */
+ public function getAuthority();
+
+ /**
+ * Retrieve the user information component of the URI.
+ *
+ * If no user information is present, this method MUST return an empty
+ * string.
+ *
+ * If a user is present in the URI, this will return that value;
+ * additionally, if the password is also present, it will be appended to the
+ * user value, with a colon (":") separating the values.
+ *
+ * The trailing "@" character is not part of the user information and MUST
+ * NOT be added.
+ *
+ * @return string The URI user information, in "username[:password]" format.
+ */
+ public function getUserInfo();
+
+ /**
+ * Retrieve the host component of the URI.
+ *
+ * If no host is present, this method MUST return an empty string.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.2.2.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
+ * @return string The URI host.
+ */
+ public function getHost();
+
+ /**
+ * Retrieve the port component of the URI.
+ *
+ * If a port is present, and it is non-standard for the current scheme,
+ * this method MUST return it as an integer. If the port is the standard port
+ * used with the current scheme, this method SHOULD return null.
+ *
+ * If no port is present, and no scheme is present, this method MUST return
+ * a null value.
+ *
+ * If no port is present, but a scheme is present, this method MAY return
+ * the standard port for that scheme, but SHOULD return null.
+ *
+ * @return null|int The URI port.
+ */
+ public function getPort();
+
+ /**
+ * Retrieve the path component of the URI.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * Normally, the empty path "" and absolute path "/" are considered equal as
+ * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
+ * do this normalization because in contexts with a trimmed base path, e.g.
+ * the front controller, this difference becomes significant. It's the task
+ * of the user to handle both "" and "/".
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.3.
+ *
+ * As an example, if the value should include a slash ("/") not intended as
+ * delimiter between path segments, that value MUST be passed in encoded
+ * form (e.g., "%2F") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.3
+ * @return string The URI path.
+ */
+ public function getPath();
+
+ /**
+ * Retrieve the query string of the URI.
+ *
+ * If no query string is present, this method MUST return an empty string.
+ *
+ * The leading "?" character is not part of the query and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.4.
+ *
+ * As an example, if a value in a key/value pair of the query string should
+ * include an ampersand ("&") not intended as a delimiter between values,
+ * that value MUST be passed in encoded form (e.g., "%26") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.4
+ * @return string The URI query string.
+ */
+ public function getQuery();
+
+ /**
+ * Retrieve the fragment component of the URI.
+ *
+ * If no fragment is present, this method MUST return an empty string.
+ *
+ * The leading "#" character is not part of the fragment and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.5.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.5
+ * @return string The URI fragment.
+ */
+ public function getFragment();
+
+ /**
+ * Return an instance with the specified scheme.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified scheme.
+ *
+ * Implementations MUST support the schemes "http" and "https" case
+ * insensitively, and MAY accommodate other schemes if required.
+ *
+ * An empty scheme is equivalent to removing the scheme.
+ *
+ * @param string $scheme The scheme to use with the new instance.
+ * @return static A new instance with the specified scheme.
+ * @throws \InvalidArgumentException for invalid or unsupported schemes.
+ */
+ public function withScheme(string $scheme);
+
+ /**
+ * Return an instance with the specified user information.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user information.
+ *
+ * Password is optional, but the user information MUST include the
+ * user; an empty string for the user is equivalent to removing user
+ * information.
+ *
+ * @param string $user The user name to use for authority.
+ * @param null|string $password The password associated with $user.
+ * @return static A new instance with the specified user information.
+ */
+ public function withUserInfo(string $user, ?string $password = null);
+
+ /**
+ * Return an instance with the specified host.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified host.
+ *
+ * An empty host value is equivalent to removing the host.
+ *
+ * @param string $host The hostname to use with the new instance.
+ * @return static A new instance with the specified host.
+ * @throws \InvalidArgumentException for invalid hostnames.
+ */
+ public function withHost(string $host);
+
+ /**
+ * Return an instance with the specified port.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified port.
+ *
+ * Implementations MUST raise an exception for ports outside the
+ * established TCP and UDP port ranges.
+ *
+ * A null value provided for the port is equivalent to removing the port
+ * information.
+ *
+ * @param null|int $port The port to use with the new instance; a null value
+ * removes the port information.
+ * @return static A new instance with the specified port.
+ * @throws \InvalidArgumentException for invalid ports.
+ */
+ public function withPort(?int $port);
+
+ /**
+ * Return an instance with the specified path.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified path.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * If the path is intended to be domain-relative rather than path relative then
+ * it must begin with a slash ("/"). Paths not starting with a slash ("/")
+ * are assumed to be relative to some base path known to the application or
+ * consumer.
+ *
+ * Users can provide both encoded and decoded path characters.
+ * Implementations ensure the correct encoding as outlined in getPath().
+ *
+ * @param string $path The path to use with the new instance.
+ * @return static A new instance with the specified path.
+ * @throws \InvalidArgumentException for invalid paths.
+ */
+ public function withPath(string $path);
+
+ /**
+ * Return an instance with the specified query string.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified query string.
+ *
+ * Users can provide both encoded and decoded query characters.
+ * Implementations ensure the correct encoding as outlined in getQuery().
+ *
+ * An empty query string value is equivalent to removing the query string.
+ *
+ * @param string $query The query string to use with the new instance.
+ * @return static A new instance with the specified query string.
+ * @throws \InvalidArgumentException for invalid query strings.
+ */
+ public function withQuery(string $query);
+
+ /**
+ * Return an instance with the specified URI fragment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified URI fragment.
+ *
+ * Users can provide both encoded and decoded fragment characters.
+ * Implementations ensure the correct encoding as outlined in getFragment().
+ *
+ * An empty fragment value is equivalent to removing the fragment.
+ *
+ * @param string $fragment The fragment to use with the new instance.
+ * @return static A new instance with the specified fragment.
+ */
+ public function withFragment(string $fragment);
+
+ /**
+ * Return the string representation as a URI reference.
+ *
+ * Depending on which components of the URI are present, the resulting
+ * string is either a full URI or relative reference according to RFC 3986,
+ * Section 4.1. The method concatenates the various components of the URI,
+ * using the appropriate delimiters:
+ *
+ * - If a scheme is present, it MUST be suffixed by ":".
+ * - If an authority is present, it MUST be prefixed by "//".
+ * - The path can be concatenated without delimiters. But there are two
+ * cases where the path has to be adjusted to make the URI reference
+ * valid as PHP does not allow to throw an exception in __toString():
+ * - If the path is rootless and an authority is present, the path MUST
+ * be prefixed by "/".
+ * - If the path is starting with more than one "/" and no authority is
+ * present, the starting slashes MUST be reduced to one.
+ * - If a query is present, it MUST be prefixed by "?".
+ * - If a fragment is present, it MUST be prefixed by "#".
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
+ * @return string
+ */
+ public function __toString();
+}
diff --git a/api_candidatos/vendor/ralouphie/getallheaders/LICENSE b/api_candidatos/vendor/ralouphie/getallheaders/LICENSE
new file mode 100644
index 0000000..be5540c
--- /dev/null
+++ b/api_candidatos/vendor/ralouphie/getallheaders/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Ralph Khattar
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/api_candidatos/vendor/ralouphie/getallheaders/README.md b/api_candidatos/vendor/ralouphie/getallheaders/README.md
new file mode 100644
index 0000000..9430d76
--- /dev/null
+++ b/api_candidatos/vendor/ralouphie/getallheaders/README.md
@@ -0,0 +1,27 @@
+getallheaders
+=============
+
+PHP `getallheaders()` polyfill. Compatible with PHP >= 5.3.
+
+[](https://travis-ci.org/ralouphie/getallheaders)
+[](https://coveralls.io/r/ralouphie/getallheaders?branch=master)
+[](https://packagist.org/packages/ralouphie/getallheaders)
+[](https://packagist.org/packages/ralouphie/getallheaders)
+[](https://packagist.org/packages/ralouphie/getallheaders)
+
+
+This is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php).
+
+## Install
+
+For PHP version **`>= 5.6`**:
+
+```
+composer require ralouphie/getallheaders
+```
+
+For PHP version **`< 5.6`**:
+
+```
+composer require ralouphie/getallheaders "^2"
+```
diff --git a/api_candidatos/vendor/ralouphie/getallheaders/composer.json b/api_candidatos/vendor/ralouphie/getallheaders/composer.json
new file mode 100644
index 0000000..de8ce62
--- /dev/null
+++ b/api_candidatos/vendor/ralouphie/getallheaders/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "ralouphie/getallheaders",
+ "description": "A polyfill for getallheaders.",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5 || ^6.5",
+ "php-coveralls/php-coveralls": "^2.1"
+ },
+ "autoload": {
+ "files": ["src/getallheaders.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "getallheaders\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/ralouphie/getallheaders/src/getallheaders.php b/api_candidatos/vendor/ralouphie/getallheaders/src/getallheaders.php
new file mode 100644
index 0000000..c7285a5
--- /dev/null
+++ b/api_candidatos/vendor/ralouphie/getallheaders/src/getallheaders.php
@@ -0,0 +1,46 @@
+ 'Content-Type',
+ 'CONTENT_LENGTH' => 'Content-Length',
+ 'CONTENT_MD5' => 'Content-Md5',
+ );
+
+ foreach ($_SERVER as $key => $value) {
+ if (substr($key, 0, 5) === 'HTTP_') {
+ $key = substr($key, 5);
+ if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {
+ $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
+ $headers[$key] = $value;
+ }
+ } elseif (isset($copy_server[$key])) {
+ $headers[$copy_server[$key]] = $value;
+ }
+ }
+
+ if (!isset($headers['Authorization'])) {
+ if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
+ $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
+ } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
+ $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
+ $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
+ } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
+ $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
+ }
+ }
+
+ return $headers;
+ }
+
+}
diff --git a/api_candidatos/vendor/slim/psr7/LICENSE.md b/api_candidatos/vendor/slim/psr7/LICENSE.md
new file mode 100644
index 0000000..2bd2d5a
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/LICENSE.md
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Slim Framework
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/api_candidatos/vendor/slim/psr7/composer.json b/api_candidatos/vendor/slim/psr7/composer.json
new file mode 100644
index 0000000..b96da46
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/composer.json
@@ -0,0 +1,76 @@
+{
+ "name": "slim/psr7",
+ "type": "library",
+ "description": "Strict PSR-7 implementation",
+ "keywords": ["psr7","psr-7","http"],
+ "homepage": "https://www.slimframework.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Josh Lockhart",
+ "email": "hello@joshlockhart.com",
+ "homepage": "https://joshlockhart.com"
+ },
+ {
+ "name": "Andrew Smith",
+ "email": "a.smith@silentworks.co.uk",
+ "homepage": "https://silentworks.co.uk"
+ },
+ {
+ "name": "Rob Allen",
+ "email": "rob@akrabat.com",
+ "homepage": "https://akrabat.com"
+ },
+ {
+ "name": "Pierre Berube",
+ "email": "pierre@lgse.com",
+ "homepage": "https://www.lgse.com"
+ }
+ ],
+ "require": {
+ "php": "^8.0",
+ "fig/http-message-util": "^1.1.5",
+ "psr/http-factory": "^1.1",
+ "psr/http-message": "^1.0 || ^2.0",
+ "ralouphie/getallheaders": "^3.0",
+ "symfony/polyfill-php80": "^1.29"
+ },
+ "require-dev": {
+ "ext-json": "*",
+ "adriansuter/php-autoload-override": "^1.4",
+ "http-interop/http-factory-tests": "^1.0 || ^2.0",
+ "php-http/psr7-integration-tests": "^1.4",
+ "phpspec/prophecy": "^1.19",
+ "phpspec/prophecy-phpunit": "^2.2",
+ "phpstan/phpstan": "^2.1",
+ "phpunit/phpunit": "^9.6 || ^10",
+ "squizlabs/php_codesniffer": "^3.10"
+ },
+ "provide": {
+ "psr/http-message-implementation": "^1.0 || ^2.0",
+ "psr/http-factory-implementation": "^1.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Slim\\Psr7\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Slim\\Tests\\Psr7\\": "tests"
+ }
+ },
+ "scripts": {
+ "test": [
+ "@phpunit",
+ "@phpcs",
+ "@phpstan"
+ ],
+ "phpunit": "@php phpunit",
+ "phpcs": "@php phpcs",
+ "phpstan": "@php phpstan --memory-limit=-1"
+ },
+ "config": {
+ "sort-packages": true
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/phpunit.xml.dist b/api_candidatos/vendor/slim/psr7/phpunit.xml.dist
new file mode 100644
index 0000000..a65dc57
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/phpunit.xml.dist
@@ -0,0 +1,23 @@
+
+
+
+
+ tests
+
+
+
+
+
+ src
+
+
+
+
+
+
diff --git a/api_candidatos/vendor/slim/psr7/src/Cookies.php b/api_candidatos/vendor/slim/psr7/src/Cookies.php
new file mode 100644
index 0000000..044d438
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Cookies.php
@@ -0,0 +1,218 @@
+ '',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => false,
+ 'httponly' => false,
+ 'samesite' => null
+ ];
+
+ /**
+ * @param array $cookies
+ */
+ public function __construct(array $cookies = [])
+ {
+ $this->requestCookies = $cookies;
+ }
+
+ /**
+ * Set default cookie properties
+ *
+ * @param array $settings
+ *
+ * @return static
+ */
+ public function setDefaults(array $settings): self
+ {
+ $this->defaults = array_replace($this->defaults, $settings);
+
+ return $this;
+ }
+
+ /**
+ * Get cookie
+ *
+ * @param string $name
+ * @param string|array|null $default
+ * @return mixed|null
+ */
+ public function get(string $name, $default = null)
+ {
+ return array_key_exists($name, $this->requestCookies) ? $this->requestCookies[$name] : $default;
+ }
+
+ /**
+ * Set cookie
+ *
+ * @param string $name
+ * @param string|array $value
+ * @return static
+ */
+ public function set(string $name, $value): self
+ {
+ if (!is_array($value)) {
+ $value = ['value' => $value];
+ }
+
+ $this->responseCookies[$name] = array_replace($this->defaults, $value);
+
+ return $this;
+ }
+
+ /**
+ * Convert all response cookies into an associate array of header values
+ *
+ * @return array
+ */
+ public function toHeaders(): array
+ {
+ $headers = [];
+
+ foreach ($this->responseCookies as $name => $properties) {
+ $headers[] = $this->toHeader($name, $properties);
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Convert to `Set-Cookie` header
+ *
+ * @param string $name Cookie name
+ * @param array $properties Cookie properties
+ *
+ * @return string
+ */
+ protected function toHeader(string $name, array $properties): string
+ {
+ $result = urlencode($name) . '=' . urlencode($properties['value']);
+
+ if (isset($properties['domain'])) {
+ $result .= '; domain=' . $properties['domain'];
+ }
+
+ if (isset($properties['path'])) {
+ $result .= '; path=' . $properties['path'];
+ }
+
+ if (isset($properties['expires'])) {
+ if (is_string($properties['expires'])) {
+ $timestamp = strtotime($properties['expires']);
+ } else {
+ $timestamp = (int) $properties['expires'];
+ }
+ if ($timestamp && $timestamp !== 0) {
+ $result .= '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp);
+ }
+ }
+
+ if (isset($properties['secure']) && $properties['secure']) {
+ $result .= '; secure';
+ }
+
+ if (isset($properties['hostonly']) && $properties['hostonly']) {
+ $result .= '; HostOnly';
+ }
+
+ if (isset($properties['httponly']) && $properties['httponly']) {
+ $result .= '; HttpOnly';
+ }
+
+ if (
+ isset($properties['samesite'])
+ && in_array(strtolower($properties['samesite']), ['lax', 'strict', 'none'], true)
+ ) {
+ // While strtolower is needed for correct comparison, the RFC doesn't care about case
+ $result .= '; SameSite=' . $properties['samesite'];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Parse cookie values from header value
+ *
+ * Returns an associative array of cookie names and values
+ *
+ * @param string|array $header
+ *
+ * @return array
+ */
+ public static function parseHeader($header): array
+ {
+ if (is_array($header)) {
+ $header = $header[0] ?? '';
+ }
+
+ if (!is_string($header)) {
+ throw new InvalidArgumentException('Cannot parse Cookie data. Header value must be a string.');
+ }
+
+ $header = rtrim($header, "\r\n");
+ $pieces = preg_split('@[;]\s*@', $header);
+ $cookies = [];
+
+ if (is_array($pieces)) {
+ foreach ($pieces as $cookie) {
+ $cookie = explode('=', $cookie, 2);
+
+ if (count($cookie) === 2) {
+ $key = urldecode($cookie[0]);
+ $value = urldecode($cookie[1]);
+
+ if (!isset($cookies[$key])) {
+ $cookies[$key] = $value;
+ }
+ }
+ }
+ }
+
+ return $cookies;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Environment.php b/api_candidatos/vendor/slim/psr7/src/Environment.php
new file mode 100644
index 0000000..55f187b
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Environment.php
@@ -0,0 +1,55 @@
+ 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
+ 'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
+ 'HTTP_USER_AGENT' => 'Slim Framework',
+ 'QUERY_STRING' => '',
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'REQUEST_METHOD' => 'GET',
+ 'REQUEST_SCHEME' => $scheme,
+ 'REQUEST_TIME' => time(),
+ 'REQUEST_TIME_FLOAT' => microtime(true),
+ 'REQUEST_URI' => '',
+ 'SCRIPT_NAME' => '',
+ 'SERVER_NAME' => 'localhost',
+ 'SERVER_PORT' => $port,
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ ], $data);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Factory/RequestFactory.php b/api_candidatos/vendor/slim/psr7/src/Factory/RequestFactory.php
new file mode 100644
index 0000000..e825ee3
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Factory/RequestFactory.php
@@ -0,0 +1,59 @@
+streamFactory = $streamFactory ?? new StreamFactory();
+ $this->uriFactory = $uriFactory ?? new UriFactory();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createRequest(string $method, $uri): RequestInterface
+ {
+ if (is_string($uri)) {
+ $uri = $this->uriFactory->createUri($uri);
+ }
+
+ if (!$uri instanceof UriInterface) {
+ throw new InvalidArgumentException(
+ 'Parameter 2 of RequestFactory::createRequest() must be a string or a compatible UriInterface.'
+ );
+ }
+
+ $body = $this->streamFactory->createStream();
+
+ return new Request($method, $uri, new Headers(), [], [], $body);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Factory/ResponseFactory.php b/api_candidatos/vendor/slim/psr7/src/Factory/ResponseFactory.php
new file mode 100644
index 0000000..c1a23a7
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Factory/ResponseFactory.php
@@ -0,0 +1,35 @@
+withStatus($code, $reasonPhrase);
+ }
+
+ return $res;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Factory/ServerRequestFactory.php b/api_candidatos/vendor/slim/psr7/src/Factory/ServerRequestFactory.php
new file mode 100644
index 0000000..5d1225d
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Factory/ServerRequestFactory.php
@@ -0,0 +1,111 @@
+streamFactory = $streamFactory ?? new StreamFactory();
+ $this->uriFactory = $uriFactory ?? new UriFactory();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
+ {
+ if (is_string($uri)) {
+ $uri = $this->uriFactory->createUri($uri);
+ }
+
+ if (!$uri instanceof UriInterface) {
+ throw new InvalidArgumentException('URI must either be string or instance of ' . UriInterface::class);
+ }
+
+ $body = $this->streamFactory->createStream();
+ $headers = new Headers();
+ $cookies = [];
+
+ if (!empty($serverParams)) {
+ $headers = Headers::createFromGlobals();
+ $cookies = Cookies::parseHeader($headers->getHeader('Cookie', []));
+ }
+
+ return new Request($method, $uri, $headers, $cookies, $serverParams, $body);
+ }
+
+ /**
+ * Create new ServerRequest from environment.
+ *
+ * @internal This method is not part of PSR-17
+ *
+ * @return Request
+ */
+ public static function createFromGlobals(): Request
+ {
+ /** @var string $method */
+ $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
+ $uri = (new UriFactory())->createFromGlobals($_SERVER);
+
+ $headers = Headers::createFromGlobals();
+ $cookies = Cookies::parseHeader($headers->getHeader('Cookie', []));
+
+ // Cache the php://input stream as it cannot be re-read
+ $cacheResource = fopen('php://temp', 'wb+');
+ $cache = $cacheResource ? new Stream($cacheResource) : null;
+
+ $body = (new StreamFactory())->createStreamFromFile('php://input', 'r', $cache);
+ $uploadedFiles = UploadedFile::createFromGlobals($_SERVER);
+
+ $request = new Request($method, $uri, $headers, $cookies, $_SERVER, $body, $uploadedFiles);
+ $contentTypes = $request->getHeader('Content-Type');
+
+ $parsedContentType = '';
+ foreach ($contentTypes as $contentType) {
+ $fragments = explode(';', $contentType);
+ $parsedContentType = current($fragments);
+ }
+
+ $contentTypesWithParsedBodies = ['application/x-www-form-urlencoded', 'multipart/form-data'];
+ if ($method === 'POST' && in_array($parsedContentType, $contentTypesWithParsedBodies)) {
+ return $request->withParsedBody($_POST);
+ }
+
+ return $request;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Factory/StreamFactory.php b/api_candidatos/vendor/slim/psr7/src/Factory/StreamFactory.php
new file mode 100644
index 0000000..04d22a1
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Factory/StreamFactory.php
@@ -0,0 +1,95 @@
+createStreamFromResource($resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createStreamFromFile(
+ string $filename,
+ string $mode = 'r',
+ ?StreamInterface $cache = null
+ ): StreamInterface {
+ set_error_handler(
+ static function (int $errno, string $errstr) use ($filename, $mode): void {
+ throw new RuntimeException(
+ "Unable to open $filename using mode $mode: $errstr",
+ $errno
+ );
+ }
+ );
+
+ try {
+ $resource = fopen($filename, $mode);
+ } catch (ValueError $exception) {
+ throw new RuntimeException("Unable to open $filename using mode $mode: " . $exception->getMessage());
+ } finally {
+ restore_error_handler();
+ }
+
+ if (!is_resource($resource)) {
+ throw new RuntimeException(
+ "StreamFactory::createStreamFromFile() could not create resource from file `$filename`"
+ );
+ }
+
+ return new Stream($resource, $cache);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createStreamFromResource($resource, ?StreamInterface $cache = null): StreamInterface
+ {
+ if (!is_resource($resource)) {
+ throw new InvalidArgumentException(
+ 'Parameter 1 of StreamFactory::createStreamFromResource() must be a resource.'
+ );
+ }
+
+ return new Stream($resource, $cache);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Factory/UploadedFileFactory.php b/api_candidatos/vendor/slim/psr7/src/Factory/UploadedFileFactory.php
new file mode 100644
index 0000000..5699e96
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Factory/UploadedFileFactory.php
@@ -0,0 +1,47 @@
+getMetadata('uri');
+
+ if (!is_string($file) || !$stream->isReadable()) {
+ throw new InvalidArgumentException('File is not readable.');
+ }
+
+ if ($size === null) {
+ $size = $stream->getSize();
+ }
+
+ return new UploadedFile($stream, $clientFilename, $clientMediaType, $size, $error);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Factory/UriFactory.php b/api_candidatos/vendor/slim/psr7/src/Factory/UriFactory.php
new file mode 100644
index 0000000..74ab377
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Factory/UriFactory.php
@@ -0,0 +1,113 @@
+ 1) {
+ $queryString = parse_url('https://www.example.com' . $globals['REQUEST_URI'], PHP_URL_QUERY) ?? '';
+ }
+ }
+
+ // Build Uri and return
+ return new Uri($scheme, $host, $port, $requestUri, $queryString, '', $username, $password);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Header.php b/api_candidatos/vendor/slim/psr7/src/Header.php
new file mode 100644
index 0000000..ef9e196
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Header.php
@@ -0,0 +1,63 @@
+originalName = $originalName;
+ $this->normalizedName = $normalizedName;
+ $this->values = $values;
+ }
+
+ public function getOriginalName(): string
+ {
+ return $this->originalName;
+ }
+
+ public function getNormalizedName(): string
+ {
+ return $this->normalizedName;
+ }
+
+ public function addValue(string $value): self
+ {
+ $this->values[] = $value;
+
+ return $this;
+ }
+
+ public function addValues(array|string $values): self
+ {
+ if (is_string($values)) {
+ return $this->addValue($values);
+ }
+
+ $this->values = array_merge($this->values, $values);
+
+ return $this;
+ }
+
+ public function getValues(): array
+ {
+ return $this->values;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Headers.php b/api_candidatos/vendor/slim/psr7/src/Headers.php
new file mode 100644
index 0000000..cc345dd
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Headers.php
@@ -0,0 +1,318 @@
+globals = $globals ?? $_SERVER;
+ $this->setHeaders($headers);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addHeader($name, $value): HeadersInterface
+ {
+ [$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value);
+
+ if (isset($this->headers[$normalizedName])) {
+ $header = $this->headers[$normalizedName];
+ $header->addValues($values);
+ } else {
+ $this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeHeader(string $name): HeadersInterface
+ {
+ $name = $this->normalizeHeaderName($name);
+ unset($this->headers[$name]);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeader(string $name, $default = []): array
+ {
+ $name = $this->normalizeHeaderName($name);
+
+ if (isset($this->headers[$name])) {
+ $header = $this->headers[$name];
+ return $header->getValues();
+ }
+
+ if (empty($default)) {
+ return $default;
+ }
+
+ $this->validateHeader($name, $default);
+ return $this->trimHeaderValue($default);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setHeader($name, $value): HeadersInterface
+ {
+ [$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value);
+
+ // Ensure we preserve original case if the header already exists in the stack
+ if (isset($this->headers[$normalizedName])) {
+ $existingHeader = $this->headers[$normalizedName];
+ $originalName = $existingHeader->getOriginalName();
+ }
+
+ $this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setHeaders(array $headers): HeadersInterface
+ {
+ $this->headers = [];
+
+ foreach ($this->parseAuthorizationHeader($headers) as $name => $value) {
+ $this->addHeader($name, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasHeader(string $name): bool
+ {
+ $name = $this->normalizeHeaderName($name);
+ return isset($this->headers[$name]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeaders(bool $originalCase = false): array
+ {
+ $headers = [];
+
+ foreach ($this->headers as $header) {
+ $name = $originalCase ? $header->getOriginalName() : $header->getNormalizedName();
+ $headers[$name] = $header->getValues();
+ }
+
+ return $headers;
+ }
+
+ /**
+ * @param string $name
+ * @param bool $preserveCase
+ * @return string
+ */
+ protected function normalizeHeaderName(string $name, bool $preserveCase = false): string
+ {
+ $name = strtr($name, '_', '-');
+
+ if (!$preserveCase) {
+ $name = strtolower($name);
+ }
+
+ if (strpos(strtolower($name), 'http-') === 0) {
+ $name = substr($name, 5);
+ }
+
+ return $name;
+ }
+
+ /**
+ * Parse incoming headers and determine Authorization header from original headers
+ *
+ * @param array $headers
+ * @return array
+ */
+ protected function parseAuthorizationHeader(array $headers): array
+ {
+ $hasAuthorizationHeader = false;
+ foreach ($headers as $name => $value) {
+ if (strtolower((string) $name) === 'authorization') {
+ $hasAuthorizationHeader = true;
+ break;
+ }
+ }
+
+ if (!$hasAuthorizationHeader) {
+ if (isset($this->globals['REDIRECT_HTTP_AUTHORIZATION'])) {
+ $headers['Authorization'] = $this->globals['REDIRECT_HTTP_AUTHORIZATION'];
+ } elseif (isset($this->globals['PHP_AUTH_USER'])) {
+ $pw = $this->globals['PHP_AUTH_PW'] ?? '';
+ $headers['Authorization'] = 'Basic ' . base64_encode($this->globals['PHP_AUTH_USER'] . ':' . $pw);
+ } elseif (isset($this->globals['PHP_AUTH_DIGEST'])) {
+ $headers['Authorization'] = $this->globals['PHP_AUTH_DIGEST'];
+ }
+ }
+
+ return $headers;
+ }
+
+ /**
+ * @param array|string $value
+ *
+ * @return array
+ */
+ protected function trimHeaderValue($value): array
+ {
+ $items = is_array($value) ? $value : [$value];
+ $result = [];
+ foreach ($items as $item) {
+ $result[] = trim((string) $item, " \t");
+ }
+ return $result;
+ }
+
+ /**
+ * @param string $name
+ * @param array|string $value
+ *
+ * @throws InvalidArgumentException
+ *
+ * @return array
+ */
+ protected function prepareHeader($name, $value): array
+ {
+ $this->validateHeader($name, $value);
+ $values = $this->trimHeaderValue($value);
+ $originalName = $this->normalizeHeaderName($name, true);
+ $normalizedName = $this->normalizeHeaderName($name);
+ return [$values, $originalName, $normalizedName];
+ }
+
+ /**
+ * Make sure the header complies with RFC 7230.
+ *
+ * Header names must be a non-empty string consisting of token characters.
+ *
+ * Header values must be strings consisting of visible characters with all optional
+ * leading and trailing whitespace stripped. This method will always strip such
+ * optional whitespace. Note that the method does not allow folding whitespace within
+ * the values as this was deprecated for almost all instances by the RFC.
+ *
+ * header-field = field-name ":" OWS field-value OWS
+ * field-name = 1*( "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^"
+ * / "_" / "`" / "|" / "~" / %x30-39 / ( %x41-5A / %x61-7A ) )
+ * OWS = *( SP / HTAB )
+ * field-value = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] )
+ *
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
+ *
+ * @param string $name
+ * @param array|string $value
+ *
+ * @throws InvalidArgumentException
+ */
+ protected function validateHeader($name, $value): void
+ {
+ $this->validateHeaderName($name);
+ $this->validateHeaderValue($value);
+ }
+
+ /**
+ * @param mixed $name
+ *
+ * @throws InvalidArgumentException
+ */
+ protected function validateHeaderName($name): void
+ {
+ if (!is_string($name) || preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@D", $name) !== 1) {
+ throw new InvalidArgumentException('Header name must be an RFC 7230 compatible string.');
+ }
+ }
+
+ /**
+ * @param mixed $value
+ *
+ * @throws InvalidArgumentException
+ */
+ protected function validateHeaderValue($value): void
+ {
+ $items = is_array($value) ? $value : [$value];
+
+ if (empty($items)) {
+ throw new InvalidArgumentException(
+ 'Header values must be a string or an array of strings, empty array given.'
+ );
+ }
+
+ $pattern = "@^[ \t\x21-\x7E\x80-\xFF]*$@D";
+ foreach ($items as $item) {
+ $hasInvalidType = !is_numeric($item) && !is_string($item);
+ $rejected = $hasInvalidType || preg_match($pattern, (string) $item) !== 1;
+ if ($rejected) {
+ throw new InvalidArgumentException(
+ 'Header values must be RFC 7230 compatible strings.'
+ );
+ }
+ }
+ }
+
+ /**
+ * @return static
+ */
+ public static function createFromGlobals()
+ {
+ $headers = null;
+
+ if (function_exists('getallheaders')) {
+ $headers = getallheaders();
+ }
+
+ if (!is_array($headers)) {
+ $headers = [];
+ }
+
+ return new static($headers);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Interfaces/HeadersInterface.php b/api_candidatos/vendor/slim/psr7/src/Interfaces/HeadersInterface.php
new file mode 100644
index 0000000..3f486f1
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Interfaces/HeadersInterface.php
@@ -0,0 +1,90 @@
+ true,
+ '1.1' => true,
+ '2.0' => true,
+ '2' => true,
+ ];
+
+ /**
+ * @var HeadersInterface
+ */
+ protected $headers;
+
+ /**
+ * @var StreamInterface
+ */
+ protected $body;
+
+ /**
+ * Disable magic setter to ensure immutability
+ *
+ * @param string $name The property name
+ * @param mixed $value The property value
+ *
+ * @return void
+ */
+ public function __set($name, $value): void
+ {
+ // Do nothing
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProtocolVersion(): string
+ {
+ return $this->protocolVersion;
+ }
+
+ /**
+ * @return static
+ * {@inheritdoc}
+ */
+ public function withProtocolVersion($version): MessageInterface
+ {
+ if (!isset(self::$validProtocolVersions[$version])) {
+ throw new InvalidArgumentException(
+ 'Invalid HTTP version. Must be one of: '
+ . implode(', ', array_keys(self::$validProtocolVersions))
+ );
+ }
+
+ $clone = clone $this;
+ $clone->protocolVersion = $version;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeaders(): array
+ {
+ return $this->headers->getHeaders(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasHeader($name): bool
+ {
+ return $this->headers->hasHeader($name);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeader($name): array
+ {
+ return $this->headers->getHeader($name);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeaderLine($name): string
+ {
+ $values = $this->headers->getHeader($name);
+ return implode(',', $values);
+ }
+
+ /**
+ * @return static
+ * {@inheritdoc}
+ */
+ public function withHeader($name, $value): MessageInterface
+ {
+ $clone = clone $this;
+ $clone->headers->setHeader($name, $value);
+
+ if ($this instanceof Response && $this->body instanceof NonBufferedBody) {
+ header(sprintf('%s: %s', $name, $clone->getHeaderLine($name)));
+ }
+
+ return $clone;
+ }
+
+ /**
+ * @return static
+ * {@inheritdoc}
+ */
+ public function withAddedHeader($name, $value): MessageInterface
+ {
+ $clone = clone $this;
+ $clone->headers->addHeader($name, $value);
+
+ if ($this instanceof Response && $this->body instanceof NonBufferedBody) {
+ header(sprintf('%s: %s', $name, $clone->getHeaderLine($name)));
+ }
+
+ return $clone;
+ }
+
+ /**
+ * @return static
+ * {@inheritdoc}
+ */
+ public function withoutHeader($name): MessageInterface
+ {
+ $clone = clone $this;
+ $clone->headers->removeHeader($name);
+
+ if ($this instanceof Response && $this->body instanceof NonBufferedBody) {
+ header_remove($name);
+ }
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getBody(): StreamInterface
+ {
+ return $this->body;
+ }
+
+ /**
+ * @return static
+ * {@inheritdoc}
+ */
+ public function withBody(StreamInterface $body): MessageInterface
+ {
+ $clone = clone $this;
+ $clone->body = $body;
+
+ return $clone;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/NonBufferedBody.php b/api_candidatos/vendor/slim/psr7/src/NonBufferedBody.php
new file mode 100644
index 0000000..ad22c2d
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/NonBufferedBody.php
@@ -0,0 +1,153 @@
+method = $this->filterMethod($method);
+ $this->uri = $uri;
+ $this->headers = $headers;
+ $this->cookies = $cookies;
+ $this->serverParams = $serverParams;
+ $this->attributes = [];
+ $this->body = $body;
+ $this->uploadedFiles = $uploadedFiles;
+
+ if (isset($serverParams['SERVER_PROTOCOL'])) {
+ $this->protocolVersion = str_replace('HTTP/', '', $serverParams['SERVER_PROTOCOL']);
+ }
+
+ if (!$this->headers->hasHeader('Host') || $this->uri->getHost() !== '') {
+ $this->headers->setHeader('Host', $this->uri->getHost());
+ }
+ }
+
+ /**
+ * This method is applied to the cloned object after PHP performs an initial shallow-copy.
+ * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers.
+ */
+ public function __clone()
+ {
+ $this->headers = clone $this->headers;
+ $this->body = clone $this->body;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMethod(): string
+ {
+ return $this->method;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withMethod($method): RequestInterface
+ {
+ $method = $this->filterMethod($method);
+ $clone = clone $this;
+ $clone->method = $method;
+
+ return $clone;
+ }
+
+ /**
+ * Validate the HTTP method
+ *
+ * @param string $method
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException on invalid HTTP method.
+ */
+ protected function filterMethod($method): string
+ {
+ /** @var mixed $method */
+ if (!is_string($method)) {
+ throw new InvalidArgumentException(sprintf(
+ 'Unsupported HTTP method; must be a string, received %s',
+ (is_object($method) ? get_class($method) : gettype($method))
+ ));
+ }
+
+ if (preg_match("/^[!#$%&'*+.^_`|~0-9a-z-]+$/i", $method) !== 1) {
+ throw new InvalidArgumentException(sprintf(
+ 'Unsupported HTTP method "%s" provided',
+ $method
+ ));
+ }
+
+ return $method;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTarget(): string
+ {
+ if ($this->requestTarget) {
+ return $this->requestTarget;
+ }
+
+ if ($this->uri === null) {
+ return '/';
+ }
+
+ $path = $this->uri->getPath();
+ $path = '/' . ltrim($path, '/');
+
+ $query = $this->uri->getQuery();
+ if ($query) {
+ $path .= '?' . $query;
+ }
+
+ return $path;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withRequestTarget($requestTarget): RequestInterface
+ {
+ if (!is_string($requestTarget) || preg_match('#\s#', $requestTarget)) {
+ throw new InvalidArgumentException(
+ 'Invalid request target provided; must be a string and cannot contain whitespace'
+ );
+ }
+
+ $clone = clone $this;
+ $clone->requestTarget = $requestTarget;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUri(): UriInterface
+ {
+ return $this->uri;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withUri(UriInterface $uri, $preserveHost = false): RequestInterface
+ {
+ $clone = clone $this;
+ $clone->uri = $uri;
+
+ if (!$preserveHost && $uri->getHost() !== '') {
+ $clone->headers->setHeader('Host', $uri->getHost());
+ return $clone;
+ }
+
+ if (($uri->getHost() !== '' && !$this->hasHeader('Host') || $this->getHeaderLine('Host') === '')) {
+ $clone->headers->setHeader('Host', $uri->getHost());
+ return $clone;
+ }
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCookieParams(): array
+ {
+ return $this->cookies;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withCookieParams(array $cookies): ServerRequestInterface
+ {
+ $clone = clone $this;
+ $clone->cookies = $cookies;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getQueryParams(): array
+ {
+ if (is_array($this->queryParams)) {
+ return $this->queryParams;
+ }
+
+ if ($this->uri === null) {
+ return [];
+ }
+
+ // Decode URL data
+ parse_str($this->uri->getQuery(), $this->queryParams);
+
+ return is_array($this->queryParams) ? $this->queryParams : [];
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withQueryParams(array $query): ServerRequestInterface
+ {
+ $clone = clone $this;
+ $clone->queryParams = $query;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUploadedFiles(): array
+ {
+ return $this->uploadedFiles;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
+ {
+ $clone = clone $this;
+ $clone->uploadedFiles = $uploadedFiles;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getServerParams(): array
+ {
+ return $this->serverParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttributes(): array
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return mixed
+ */
+ public function getAttribute($name, $default = null)
+ {
+ return $this->attributes[$name] ?? $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withAttribute($name, $value): ServerRequestInterface
+ {
+ $clone = clone $this;
+ $clone->attributes[$name] = $value;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withoutAttribute($name): ServerRequestInterface
+ {
+ $clone = clone $this;
+
+ unset($clone->attributes[$name]);
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParsedBody()
+ {
+ return $this->parsedBody;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withParsedBody($data): ServerRequestInterface
+ {
+ /** @var mixed $data */
+ if (!is_null($data) && !is_object($data) && !is_array($data)) {
+ throw new InvalidArgumentException('Parsed body value must be an array, an object, or null');
+ }
+
+ $clone = clone $this;
+ $clone->parsedBody = $data;
+
+ return $clone;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Response.php b/api_candidatos/vendor/slim/psr7/src/Response.php
new file mode 100644
index 0000000..980e3b5
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Response.php
@@ -0,0 +1,216 @@
+ 'Continue',
+ StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols',
+ StatusCodeInterface::STATUS_PROCESSING => 'Processing',
+
+ // Successful 2xx
+ StatusCodeInterface::STATUS_OK => 'OK',
+ StatusCodeInterface::STATUS_CREATED => 'Created',
+ StatusCodeInterface::STATUS_ACCEPTED => 'Accepted',
+ StatusCodeInterface::STATUS_NON_AUTHORITATIVE_INFORMATION => 'Non-Authoritative Information',
+ StatusCodeInterface::STATUS_NO_CONTENT => 'No Content',
+ StatusCodeInterface::STATUS_RESET_CONTENT => 'Reset Content',
+ StatusCodeInterface::STATUS_PARTIAL_CONTENT => 'Partial Content',
+ StatusCodeInterface::STATUS_MULTI_STATUS => 'Multi-Status',
+ StatusCodeInterface::STATUS_ALREADY_REPORTED => 'Already Reported',
+ StatusCodeInterface::STATUS_IM_USED => 'IM Used',
+
+ // Redirection 3xx
+ StatusCodeInterface::STATUS_MULTIPLE_CHOICES => 'Multiple Choices',
+ StatusCodeInterface::STATUS_MOVED_PERMANENTLY => 'Moved Permanently',
+ StatusCodeInterface::STATUS_FOUND => 'Found',
+ StatusCodeInterface::STATUS_SEE_OTHER => 'See Other',
+ StatusCodeInterface::STATUS_NOT_MODIFIED => 'Not Modified',
+ StatusCodeInterface::STATUS_USE_PROXY => 'Use Proxy',
+ StatusCodeInterface::STATUS_RESERVED => '(Unused)',
+ StatusCodeInterface::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect',
+ StatusCodeInterface::STATUS_PERMANENT_REDIRECT => 'Permanent Redirect',
+
+ // Client Error 4xx
+ StatusCodeInterface::STATUS_BAD_REQUEST => 'Bad Request',
+ StatusCodeInterface::STATUS_UNAUTHORIZED => 'Unauthorized',
+ StatusCodeInterface::STATUS_PAYMENT_REQUIRED => 'Payment Required',
+ StatusCodeInterface::STATUS_FORBIDDEN => 'Forbidden',
+ StatusCodeInterface::STATUS_NOT_FOUND => 'Not Found',
+ StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed',
+ StatusCodeInterface::STATUS_NOT_ACCEPTABLE => 'Not Acceptable',
+ StatusCodeInterface::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required',
+ StatusCodeInterface::STATUS_REQUEST_TIMEOUT => 'Request Timeout',
+ StatusCodeInterface::STATUS_CONFLICT => 'Conflict',
+ StatusCodeInterface::STATUS_GONE => 'Gone',
+ StatusCodeInterface::STATUS_LENGTH_REQUIRED => 'Length Required',
+ StatusCodeInterface::STATUS_PRECONDITION_FAILED => 'Precondition Failed',
+ StatusCodeInterface::STATUS_PAYLOAD_TOO_LARGE => 'Request Entity Too Large',
+ StatusCodeInterface::STATUS_URI_TOO_LONG => 'Request-URI Too Long',
+ StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type',
+ StatusCodeInterface::STATUS_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable',
+ StatusCodeInterface::STATUS_EXPECTATION_FAILED => 'Expectation Failed',
+ StatusCodeInterface::STATUS_IM_A_TEAPOT => 'I\'m a teapot',
+ StatusCodeInterface::STATUS_MISDIRECTED_REQUEST => 'Misdirected Request',
+ StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity',
+ StatusCodeInterface::STATUS_LOCKED => 'Locked',
+ StatusCodeInterface::STATUS_FAILED_DEPENDENCY => 'Failed Dependency',
+ StatusCodeInterface::STATUS_UPGRADE_REQUIRED => 'Upgrade Required',
+ StatusCodeInterface::STATUS_PRECONDITION_REQUIRED => 'Precondition Required',
+ StatusCodeInterface::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests',
+ StatusCodeInterface::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large',
+ 444 => 'Connection Closed Without Response',
+ StatusCodeInterface::STATUS_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons',
+ 499 => 'Client Closed Request',
+
+ // Server Error 5xx
+ StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error',
+ StatusCodeInterface::STATUS_NOT_IMPLEMENTED => 'Not Implemented',
+ StatusCodeInterface::STATUS_BAD_GATEWAY => 'Bad Gateway',
+ StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable',
+ StatusCodeInterface::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout',
+ StatusCodeInterface::STATUS_VERSION_NOT_SUPPORTED => 'HTTP Version Not Supported',
+ StatusCodeInterface::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates',
+ StatusCodeInterface::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage',
+ StatusCodeInterface::STATUS_LOOP_DETECTED => 'Loop Detected',
+ StatusCodeInterface::STATUS_NOT_EXTENDED => 'Not Extended',
+ StatusCodeInterface::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required',
+ 599 => 'Network Connect Timeout Error',
+ ];
+
+ /**
+ * @param int $status The response status code.
+ * @param HeadersInterface|null $headers The response headers.
+ * @param StreamInterface|null $body The response body.
+ */
+ public function __construct(
+ int $status = StatusCodeInterface::STATUS_OK,
+ ?HeadersInterface $headers = null,
+ ?StreamInterface $body = null
+ ) {
+ $this->status = $this->filterStatus($status);
+ $this->headers = $headers ?: new Headers([], []);
+ $this->body = $body ?: (new StreamFactory())->createStream();
+ }
+
+ /**
+ * This method is applied to the cloned object after PHP performs an initial shallow-copy.
+ * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers.
+ */
+ public function __clone()
+ {
+ $this->headers = clone $this->headers;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStatusCode(): int
+ {
+ return $this->status;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withStatus($code, $reasonPhrase = ''): ResponseInterface
+ {
+ $code = $this->filterStatus($code);
+ $reasonPhrase = $this->filterReasonPhrase($reasonPhrase);
+
+ $clone = clone $this;
+ $clone->status = $code;
+ $clone->reasonPhrase = $reasonPhrase;
+
+ return $clone;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getReasonPhrase(): string
+ {
+ if ($this->reasonPhrase !== '') {
+ return $this->reasonPhrase;
+ }
+
+ if (isset(static::$messages[$this->status])) {
+ return static::$messages[$this->status];
+ }
+
+ return '';
+ }
+
+ /**
+ * Filter HTTP status code.
+ *
+ * @param int $status HTTP status code.
+ *
+ * @return int
+ *
+ * @throws InvalidArgumentException If an invalid HTTP status code is provided.
+ */
+ protected function filterStatus($status): int
+ {
+ if (!is_integer($status) || $status < StatusCodeInterface::STATUS_CONTINUE || $status > 599) {
+ throw new InvalidArgumentException('Invalid HTTP status code.');
+ }
+
+ return $status;
+ }
+
+ /**
+ * Filter Reason Phrase
+ *
+ * @param mixed $reasonPhrase
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException
+ */
+ protected function filterReasonPhrase($reasonPhrase = ''): string
+ {
+ if (is_object($reasonPhrase) && method_exists($reasonPhrase, '__toString')) {
+ $reasonPhrase = (string) $reasonPhrase;
+ }
+
+ if (!is_string($reasonPhrase)) {
+ throw new InvalidArgumentException('Response reason phrase must be a string.');
+ }
+
+ if (strpos($reasonPhrase, "\r") !== false || strpos($reasonPhrase, "\n") !== false) {
+ throw new InvalidArgumentException(
+ 'Reason phrase contains one of the following prohibited characters: \r \n'
+ );
+ }
+
+ return $reasonPhrase;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Stream.php b/api_candidatos/vendor/slim/psr7/src/Stream.php
new file mode 100644
index 0000000..0431ff0
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Stream.php
@@ -0,0 +1,396 @@
+attach($stream);
+
+ if ($cache && (!$cache->isSeekable() || !$cache->isWritable())) {
+ throw new RuntimeException('Cache stream must be seekable and writable');
+ }
+ $this->cache = $cache;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return array|mixed
+ */
+ public function getMetadata($key = null)
+ {
+ if (!$this->stream) {
+ return null;
+ }
+
+ $this->meta = stream_get_meta_data($this->stream);
+
+ if (!$key) {
+ return $this->meta;
+ }
+
+ return $this->meta[$key] ?? null;
+ }
+
+ /**
+ * Attach new resource to this object.
+ *
+ * @internal This method is not part of the PSR-7 standard.
+ *
+ * @param resource $stream A PHP resource handle.
+ *
+ * @throws InvalidArgumentException If argument is not a valid PHP resource.
+ *
+ * @return void
+ */
+ protected function attach($stream): void
+ {
+ if (!is_resource($stream)) {
+ throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource');
+ }
+
+ if ($this->stream) {
+ $this->detach();
+ }
+
+ $this->stream = $stream;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ $oldResource = $this->stream;
+ $this->stream = null;
+ $this->meta = null;
+ $this->readable = null;
+ $this->writable = null;
+ $this->seekable = null;
+ $this->size = null;
+ $this->isPipe = null;
+
+ $this->cache = null;
+ $this->finished = false;
+
+ return $oldResource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString(): string
+ {
+ if (!$this->stream) {
+ return '';
+ }
+ if ($this->cache && $this->finished) {
+ $this->cache->rewind();
+ return $this->cache->getContents();
+ }
+ if ($this->isSeekable()) {
+ $this->rewind();
+ }
+ return $this->getContents();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close(): void
+ {
+ if ($this->stream) {
+ if ($this->isPipe()) {
+ pclose($this->stream);
+ } else {
+ fclose($this->stream);
+ }
+ }
+
+ $this->detach();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize(): ?int
+ {
+ if ($this->stream && !$this->size) {
+ $stats = fstat($this->stream);
+
+ if ($stats) {
+ $this->size = !$this->isPipe() ? $stats['size'] : null;
+ }
+ }
+
+ return $this->size;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function tell(): int
+ {
+ $position = false;
+
+ if ($this->stream) {
+ $position = ftell($this->stream);
+ }
+
+ if ($position === false || $this->isPipe()) {
+ throw new RuntimeException('Could not get the position of the pointer in stream.');
+ }
+
+ return $position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eof(): bool
+ {
+ return !$this->stream || feof($this->stream);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isReadable(): bool
+ {
+ if ($this->readable !== null) {
+ return $this->readable;
+ }
+
+ $this->readable = false;
+
+ if ($this->stream) {
+ $mode = $this->getMetadata('mode');
+
+ if (is_string($mode) && (strstr($mode, 'r') !== false || strstr($mode, '+') !== false)) {
+ $this->readable = true;
+ }
+ }
+
+ return $this->readable;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isWritable(): bool
+ {
+ if ($this->writable === null) {
+ $this->writable = false;
+
+ if ($this->stream) {
+ $mode = $this->getMetadata('mode');
+
+ if (is_string($mode) && (strstr($mode, 'w') !== false || strstr($mode, '+') !== false)) {
+ $this->writable = true;
+ }
+ }
+ }
+
+ return $this->writable;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isSeekable(): bool
+ {
+ if ($this->seekable === null) {
+ $this->seekable = false;
+
+ if ($this->stream) {
+ $this->seekable = !$this->isPipe() && $this->getMetadata('seekable');
+ }
+ }
+
+ return $this->seekable;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET): void
+ {
+ if (!$this->isSeekable() || $this->stream && fseek($this->stream, $offset, $whence) === -1) {
+ throw new RuntimeException('Could not seek in stream.');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rewind(): void
+ {
+ if (!$this->isSeekable() || $this->stream && rewind($this->stream) === false) {
+ throw new RuntimeException('Could not rewind stream.');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($length): string
+ {
+ $data = false;
+
+ if ($this->isReadable() && $this->stream && $length > 0) {
+ $data = fread($this->stream, $length);
+ }
+
+ if (is_string($data)) {
+ if ($this->cache) {
+ $this->cache->write($data);
+ }
+ if ($this->eof()) {
+ $this->finished = true;
+ }
+ return $data;
+ }
+
+ throw new RuntimeException('Could not read from stream.');
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return int
+ */
+ public function write($string): int
+ {
+ $written = false;
+
+ if ($this->isWritable() && $this->stream) {
+ $written = fwrite($this->stream, $string);
+ }
+
+ if ($written !== false) {
+ $this->size = null;
+ return $written;
+ }
+
+ throw new RuntimeException('Could not write to stream.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContents(): string
+ {
+ if ($this->cache && $this->finished) {
+ $this->cache->rewind();
+ return $this->cache->getContents();
+ }
+
+ $contents = false;
+
+ if ($this->stream) {
+ $contents = stream_get_contents($this->stream);
+ }
+
+ if (is_string($contents)) {
+ if ($this->cache) {
+ $this->cache->write($contents);
+ }
+ if ($this->eof()) {
+ $this->finished = true;
+ }
+ return $contents;
+ }
+
+ throw new RuntimeException('Could not get contents of stream.');
+ }
+
+ /**
+ * Returns whether or not the stream is a pipe.
+ *
+ * @internal This method is not part of the PSR-7 standard.
+ *
+ * @return bool
+ */
+ public function isPipe(): bool
+ {
+ if ($this->isPipe === null) {
+ $this->isPipe = false;
+
+ if ($this->stream) {
+ $stats = fstat($this->stream);
+
+ if (is_array($stats)) {
+ $this->isPipe = ($stats['mode'] & self::FSTAT_MODE_S_IFIFO) !== 0;
+ }
+ }
+ }
+
+ return $this->isPipe;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/UploadedFile.php b/api_candidatos/vendor/slim/psr7/src/UploadedFile.php
new file mode 100644
index 0000000..d8d6ad6
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/UploadedFile.php
@@ -0,0 +1,279 @@
+getMetadata('uri');
+ if (!is_string($file)) {
+ throw new InvalidArgumentException('No URI associated with the stream.');
+ }
+ $this->file = $file;
+ $this->stream = $fileNameOrStream;
+ } elseif (is_string($fileNameOrStream)) {
+ $this->file = $fileNameOrStream;
+ } else {
+ throw new InvalidArgumentException(
+ 'Please provide a string (full path to the uploaded file) or an instance of StreamInterface.'
+ );
+ }
+ $this->name = $name;
+ $this->type = $type;
+ $this->size = $size;
+ $this->error = $error;
+ $this->sapi = $sapi;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return StreamInterface
+ */
+ public function getStream(): StreamInterface
+ {
+ if ($this->moved) {
+ throw new RuntimeException(sprintf('Uploaded file %s has already been moved', $this->name));
+ }
+
+ if (!$this->stream) {
+ $this->stream = (new StreamFactory())->createStreamFromFile($this->file);
+ }
+
+ return $this->stream;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function moveTo($targetPath): void
+ {
+ if ($this->moved) {
+ throw new RuntimeException('Uploaded file already moved');
+ }
+
+ $targetIsStream = strpos($targetPath, '://') > 0;
+ if (!$targetIsStream && !is_writable(dirname($targetPath))) {
+ throw new InvalidArgumentException('Upload target path is not writable');
+ }
+
+ if ($targetIsStream) {
+ if (!copy($this->file, $targetPath)) {
+ throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));
+ }
+
+ if (!unlink($this->file)) {
+ throw new RuntimeException(sprintf('Error removing uploaded file %s', $this->name));
+ }
+ } elseif ($this->sapi) {
+ if (!is_uploaded_file($this->file)) {
+ throw new RuntimeException(sprintf('%s is not a valid uploaded file', $this->file));
+ }
+
+ if (!move_uploaded_file($this->file, $targetPath)) {
+ throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));
+ }
+ } else {
+ if (!rename($this->file, $targetPath)) {
+ throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));
+ }
+ }
+
+ $this->moved = true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getError(): int
+ {
+ return $this->error;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getClientFilename(): ?string
+ {
+ return $this->name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getClientMediaType(): ?string
+ {
+ return $this->type;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize(): ?int
+ {
+ return $this->size;
+ }
+
+ /**
+ * Returns the client-provided full path to the file
+ *
+ * @internal This method is not part of the PSR-7 standard
+ *
+ * @return string
+ */
+ public function getFilePath(): string
+ {
+ return $this->file;
+ }
+
+ /**
+ * Create a normalized tree of UploadedFile instances from the Environment.
+ *
+ * @internal This method is not part of the PSR-7 standard.
+ *
+ * @param array $globals The global server variables.
+ *
+ * @return array A normalized tree of UploadedFile instances or null if none are provided.
+ */
+ public static function createFromGlobals(array $globals): array
+ {
+ if (isset($globals['slim.files']) && is_array($globals['slim.files'])) {
+ return $globals['slim.files'];
+ }
+
+ if (!empty($_FILES)) {
+ return self::parseUploadedFiles($_FILES);
+ }
+
+ return [];
+ }
+
+ /**
+ * Parse a non-normalized, i.e. $_FILES superglobal, tree of uploaded file data.
+ *
+ * @internal This method is not part of the PSR-7 standard.
+ *
+ * @param array $uploadedFiles The non-normalized tree of uploaded file data.
+ *
+ * @return array A normalized tree of UploadedFile instances.
+ */
+ private static function parseUploadedFiles(array $uploadedFiles): array
+ {
+ $parsed = [];
+ foreach ($uploadedFiles as $field => $uploadedFile) {
+ if (!isset($uploadedFile['error'])) {
+ if (is_array($uploadedFile)) {
+ $parsed[$field] = self::parseUploadedFiles($uploadedFile);
+ }
+ continue;
+ }
+
+ $parsed[$field] = [];
+ if (!is_array($uploadedFile['error'])) {
+ $parsed[$field] = new static(
+ $uploadedFile['tmp_name'],
+ $uploadedFile['name'] ?? null,
+ $uploadedFile['type'] ?? null,
+ $uploadedFile['size'] ?? null,
+ $uploadedFile['error'],
+ true
+ );
+ } else {
+ $subArray = [];
+ foreach ($uploadedFile['error'] as $fileIdx => $error) {
+ // Normalize sub array and re-parse to move the input's key name up a level
+ $subArray[$fileIdx]['name'] = $uploadedFile['name'][$fileIdx];
+ $subArray[$fileIdx]['type'] = $uploadedFile['type'][$fileIdx];
+ $subArray[$fileIdx]['tmp_name'] = $uploadedFile['tmp_name'][$fileIdx];
+ $subArray[$fileIdx]['error'] = $uploadedFile['error'][$fileIdx];
+ $subArray[$fileIdx]['size'] = $uploadedFile['size'][$fileIdx];
+
+ $parsed[$field] = self::parseUploadedFiles($subArray);
+ }
+ }
+ }
+
+ return $parsed;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/src/Uri.php b/api_candidatos/vendor/slim/psr7/src/Uri.php
new file mode 100644
index 0000000..6fbe47c
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/src/Uri.php
@@ -0,0 +1,505 @@
+ null,
+ 'http' => 80,
+ 'https' => 443
+ ];
+
+ /**
+ * Uri scheme (without "://" suffix)
+ */
+ protected string $scheme = '';
+
+ protected string $user = '';
+
+ protected string $password = '';
+
+ protected string $host = '';
+
+ protected ?int $port;
+
+ protected string $path = '';
+
+ /**
+ * Uri query string (without "?" prefix)
+ */
+ protected string $query = '';
+
+ /**
+ * Uri fragment string (without "#" prefix)
+ */
+ protected string $fragment = '';
+
+ /**
+ * @param string $scheme Uri scheme.
+ * @param string $host Uri host.
+ * @param int|null $port Uri port number.
+ * @param string $path Uri path.
+ * @param string $query Uri query string.
+ * @param string $fragment Uri fragment.
+ * @param string $user Uri user.
+ * @param string $password Uri password.
+ */
+ public function __construct(
+ string $scheme,
+ string $host,
+ ?int $port = null,
+ string $path = '/',
+ string $query = '',
+ string $fragment = '',
+ string $user = '',
+ string $password = ''
+ ) {
+ $this->scheme = $this->filterScheme($scheme);
+ $this->host = $this->filterHost($host);
+ $this->port = $this->filterPort($port);
+ $this->path = $this->filterPath($path);
+ $this->query = $this->filterQuery($query);
+ $this->fragment = $this->filterFragment($fragment);
+ $this->user = $this->filterUserInfo($user);
+ $this->password = $this->filterUserInfo($password);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getScheme(): string
+ {
+ return $this->scheme;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withScheme($scheme): UriInterface
+ {
+ $scheme = $this->filterScheme($scheme);
+ $clone = clone $this;
+ $clone->scheme = $scheme;
+
+ return $clone;
+ }
+
+ /**
+ * Filter Uri scheme.
+ *
+ * @param mixed $scheme Raw Uri scheme.
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException If the Uri scheme is not a string.
+ * @throws InvalidArgumentException If Uri scheme is not exists in SUPPORTED_SCHEMES
+ */
+ protected function filterScheme($scheme): string
+ {
+ if (!is_string($scheme)) {
+ throw new InvalidArgumentException('Uri scheme must be a string.');
+ }
+
+ $scheme = str_replace('://', '', strtolower($scheme));
+ if (!key_exists($scheme, static::SUPPORTED_SCHEMES)) {
+ throw new InvalidArgumentException(
+ 'Uri scheme must be one of: "' . implode('", "', array_keys(static::SUPPORTED_SCHEMES)) . '"'
+ );
+ }
+
+ return $scheme;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthority(): string
+ {
+ $userInfo = $this->getUserInfo();
+ $host = $this->getHost();
+ $port = $this->getPort();
+
+ return ($userInfo !== '' ? $userInfo . '@' : '') . $host . ($port !== null ? ':' . $port : '');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUserInfo(): string
+ {
+ $info = $this->user;
+
+ if ($this->password !== '') {
+ $info .= ':' . $this->password;
+ }
+
+ return $info;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withUserInfo($user, $password = null): UriInterface
+ {
+ $clone = clone $this;
+ $clone->user = $this->filterUserInfo($user);
+
+ if ($clone->user !== '') {
+ $clone->password = $this->filterUserInfo($password);
+ } else {
+ $clone->password = '';
+ }
+
+ return $clone;
+ }
+
+ /**
+ * Filters the user info string.
+ *
+ * Returns the percent-encoded query string.
+ *
+ * @param string|null $info The raw uri query string.
+ *
+ * @return string
+ */
+ protected function filterUserInfo(?string $info = null): string
+ {
+ if (!is_string($info)) {
+ return '';
+ }
+
+ $match = preg_replace_callback(
+ '/(?:[^%a-zA-Z0-9_\-\.~\pL!\$&\'\(\)\*\+,;=]+|%(?![A-Fa-f0-9]{2}))/',
+ function ($match) {
+ return rawurlencode($match[0]);
+ },
+ $info
+ );
+
+ return is_string($match) ? $match : '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHost(): string
+ {
+ return $this->host;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withHost($host): UriInterface
+ {
+ $clone = clone $this;
+ $clone->host = $this->filterHost($host);
+
+ return $clone;
+ }
+
+ /**
+ * Filter Uri host.
+ *
+ * If the supplied host is an IPv6 address, then it is converted to a reference
+ * as per RFC 2373.
+ *
+ * @param mixed $host The host to filter.
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException for invalid host names.
+ */
+ protected function filterHost($host): string
+ {
+ if (is_object($host) && method_exists($host, '__toString')) {
+ $host = (string) $host;
+ }
+
+ if (!is_string($host)) {
+ throw new InvalidArgumentException('Uri host must be a string');
+ }
+
+ if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ $host = '[' . $host . ']';
+ }
+
+ return strtolower($host);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPort(): ?int
+ {
+ return $this->port && !$this->hasStandardPort() ? $this->port : null;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withPort($port): UriInterface
+ {
+ $port = $this->filterPort($port);
+ $clone = clone $this;
+ $clone->port = $port;
+
+ return $clone;
+ }
+
+ /**
+ * Does this Uri use a standard port?
+ *
+ * @return bool
+ */
+ protected function hasStandardPort(): bool
+ {
+ return static::SUPPORTED_SCHEMES[$this->scheme] === $this->port;
+ }
+
+ /**
+ * Filter Uri port.
+ *
+ * @param int|string|null $port The Uri port number.
+ *
+ * @return int|null
+ *
+ * @throws InvalidArgumentException If the port is invalid.
+ */
+ protected function filterPort($port): ?int
+ {
+ if (is_null($port)) {
+ return null;
+ }
+
+ $port = (int) $port;
+
+ if ($port >= 1 && $port <= 65535) {
+ return $port;
+ }
+
+ throw new InvalidArgumentException('Uri port must be null or an integer between 1 and 65535 (inclusive)');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPath(): string
+ {
+ if (str_starts_with($this->path, '/')) {
+ // Use only one leading slash to prevent XSS attempts.
+ return '/' . ltrim($this->path, '/');
+ }
+
+ return $this->path;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withPath($path): UriInterface
+ {
+ if (!is_string($path)) {
+ throw new InvalidArgumentException('Uri path must be a string');
+ }
+
+ $clone = clone $this;
+ $clone->path = $this->filterPath($path);
+
+ return $clone;
+ }
+
+ /**
+ * Filter Uri path.
+ *
+ * This method percent-encodes all reserved characters in the provided path string.
+ * This method will NOT double-encode characters that are already percent-encoded.
+ *
+ * @param string $path The raw uri path.
+ *
+ * @return string The RFC 3986 percent-encoded uri path.
+ *
+ * @link http://www.faqs.org/rfcs/rfc3986.html
+ */
+ protected function filterPath($path): string
+ {
+ $match = preg_replace_callback(
+ '/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
+ fn (array $match) => rawurlencode($match[0]),
+ $path
+ );
+
+ return is_string($match) ? $match : '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getQuery(): string
+ {
+ return $this->query;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withQuery($query): UriInterface
+ {
+ $query = ltrim($this->filterQuery($query), '?');
+ $clone = clone $this;
+ $clone->query = $query;
+
+ return $clone;
+ }
+
+ /**
+ * Filters the query string of a URI.
+ *
+ * Returns the percent-encoded query string.
+ *
+ * @param mixed $query The raw uri query string.
+ *
+ * @return string
+ */
+ protected function filterQuery($query): string
+ {
+ if (is_object($query) && method_exists($query, '__toString')) {
+ $query = (string) $query;
+ }
+
+ if (!is_string($query)) {
+ throw new InvalidArgumentException('Uri query must be a string.');
+ }
+
+ $match = preg_replace_callback(
+ '/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
+ function ($match) {
+ return rawurlencode($match[0]);
+ },
+ $query
+ );
+
+ return is_string($match) ? $match : '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFragment(): string
+ {
+ return $this->fragment;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return static
+ */
+ public function withFragment($fragment): UriInterface
+ {
+ $fragment = $this->filterFragment($fragment);
+ $clone = clone $this;
+ $clone->fragment = $fragment;
+
+ return $clone;
+ }
+
+ /**
+ * Filters fragment of a URI.
+ *
+ * Returns the percent-encoded fragment.
+ *
+ * @param mixed $fragment The raw uri query string.
+ *
+ * @return string
+ */
+ protected function filterFragment($fragment): string
+ {
+ if (is_object($fragment) && method_exists($fragment, '__toString')) {
+ $fragment = (string) $fragment;
+ }
+
+ if (!is_string($fragment)) {
+ throw new InvalidArgumentException('Uri fragment must be a string.');
+ }
+
+ $fragment = ltrim($fragment, '#');
+
+ $match = preg_replace_callback(
+ '/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
+ function ($match) {
+ return rawurlencode($match[0]);
+ },
+ $fragment
+ );
+
+ return is_string($match) ? $match : '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString(): string
+ {
+ $scheme = $this->getScheme();
+ $authority = $this->getAuthority();
+ $path = $this->path;
+ $query = $this->getQuery();
+ $fragment = $this->getFragment();
+
+ if ($path !== '') {
+ if ($path[0] !== '/') {
+ if ($authority !== '') {
+ // If the path is rootless and an authority is present, the path MUST be prefixed by "/".
+ $path = '/' . $path;
+ }
+ } elseif (isset($path[1]) && $path[1] === '/') {
+ if ($authority === '') {
+ // If the path is starting with more than one "/" and no authority is present,
+ // the starting slashes MUST be reduced to one.
+ $path = ltrim($path, '/');
+ $path = '/' . $path;
+ }
+ }
+ }
+
+ return ($scheme !== '' ? $scheme . ':' : '')
+ . ($authority !== '' ? '//' . $authority : '')
+ . $path
+ . ($query !== '' ? '?' . $query : '')
+ . ($fragment !== '' ? '#' . $fragment : '');
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Assets/HeaderStack.php b/api_candidatos/vendor/slim/psr7/tests/Assets/HeaderStack.php
new file mode 100644
index 0000000..b07daea
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Assets/HeaderStack.php
@@ -0,0 +1,95 @@
+ $item) {
+ if (false !== strpos($item['header'], "$header:")) {
+ unset(self::$data[$key]);
+ }
+ }
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/BodyTest.php b/api_candidatos/vendor/slim/psr7/tests/BodyTest.php
new file mode 100644
index 0000000..de1d8de
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/BodyTest.php
@@ -0,0 +1,422 @@
+stream) === true) {
+ fclose($this->stream);
+ }
+ }
+
+ /**
+ * @param string $mode
+ *
+ * @return resource
+ */
+ public function resourceFactory(string $mode = 'r+')
+ {
+ $stream = fopen('php://temp', $mode);
+ fwrite($stream, $this->text);
+ rewind($stream);
+
+ return $stream;
+ }
+
+ public function testConstructorAttachesStream()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+
+ $this->assertSame($this->stream, $bodyStream->getValue($body));
+ }
+
+ public function testConstructorInvalidStream()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->stream = 'foo';
+ $body = new Stream($this->stream);
+ }
+
+ public function testGetMetadata()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertTrue(is_array($body->getMetadata()));
+ }
+
+ public function testGetMetadataKey()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertEquals('php://temp', $body->getMetadata('uri'));
+ }
+
+ public function testGetMetadataKeyNotFound()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertNull($body->getMetadata('foo'));
+ }
+
+ public function testDetach()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+
+ $bodyMetadata = new ReflectionProperty($body, 'meta');
+ $bodyMetadata->setAccessible(true);
+
+ $bodyReadable = new ReflectionProperty($body, 'readable');
+ $bodyReadable->setAccessible(true);
+
+ $bodyWritable = new ReflectionProperty($body, 'writable');
+ $bodyWritable->setAccessible(true);
+
+ $bodySeekable = new ReflectionProperty($body, 'seekable');
+ $bodySeekable->setAccessible(true);
+
+ $result = $body->detach();
+
+ $this->assertSame($this->stream, $result);
+ $this->assertNull($bodyStream->getValue($body));
+ $this->assertNull($bodyMetadata->getValue($body));
+ $this->assertNull($bodyReadable->getValue($body));
+ $this->assertNull($bodyWritable->getValue($body));
+ $this->assertNull($bodySeekable->getValue($body));
+ }
+
+ public function testToStringAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertEquals($this->text, (string) $body);
+ }
+
+ public function testToStringAttachedRewindsFirst()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertEquals($this->text, (string) $body);
+ $this->assertEquals($this->text, (string) $body);
+ $this->assertEquals($this->text, (string) $body);
+ }
+
+ public function testToStringDetached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+ $bodyStream->setValue($body, null);
+
+ $this->assertEquals('', (string) $body);
+ }
+
+ public function testClose()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->close();
+
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+
+ $this->assertNull($bodyStream->getValue($body));
+ }
+
+ public function testGetSizeAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertEquals(mb_strlen($this->text), $body->getSize());
+ }
+
+ public function testGetSizeDetached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+ $bodyStream->setValue($body, null);
+
+ $this->assertNull($body->getSize());
+ }
+
+ public function testTellAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ fseek($this->stream, 10);
+
+ $this->assertEquals(10, $body->tell());
+ }
+
+ public function testTellDetachedThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+ $bodyStream->setValue($body, null);
+
+ $body->tell();
+ }
+
+ public function testEofAttachedFalse()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ fseek($this->stream, 10);
+
+ $this->assertFalse($body->eof());
+ }
+
+ public function testEofAttachedTrue()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ while (feof($this->stream) === false) {
+ fread($this->stream, 1024);
+ }
+
+ $this->assertTrue($body->eof());
+ }
+
+ public function testEofDetached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $bodyStream = new ReflectionProperty($body, 'stream');
+ $bodyStream->setAccessible(true);
+ $bodyStream->setValue($body, null);
+
+ $this->assertTrue($body->eof());
+ }
+
+ public function isReadableAttachedTrue()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertTrue($body->isReadable());
+ }
+
+ public function isReadableAttachedFalse()
+ {
+ $stream = fopen('php://temp', 'w');
+ $body = new Stream($this->stream);
+
+ $this->assertFalse($body->isReadable());
+ fclose($stream);
+ }
+
+ public function testIsReadableDetached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $this->assertFalse($body->isReadable());
+ }
+
+ public function isWritableAttachedTrue()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertTrue($body->isWritable());
+ }
+
+ public function isWritableAttachedFalse()
+ {
+ $stream = fopen('php://temp', 'r');
+ $body = new Stream($this->stream);
+
+ $this->assertFalse($body->isWritable());
+ fclose($stream);
+ }
+
+ public function testIsWritableDetached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $this->assertFalse($body->isWritable());
+ }
+
+ public function isSeekableAttachedTrue()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertTrue($body->isSeekable());
+ }
+
+ // TODO: Is seekable is false when attached... how?
+
+ public function testIsSeekableDetached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $this->assertFalse($body->isSeekable());
+ }
+
+ public function testSeekAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->seek(10);
+
+ $this->assertEquals(10, ftell($this->stream));
+ }
+
+ public function testSeekDetachedThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $body->seek(10);
+ }
+
+ public function testRewindAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ fseek($this->stream, 10);
+ $body->rewind();
+
+ $this->assertEquals(0, ftell($this->stream));
+ }
+
+ public function testRewindDetachedThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $body->rewind();
+ }
+
+ public function testReadAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+
+ $this->assertEquals(substr($this->text, 0, 10), $body->read(10));
+ }
+
+ public function testReadDetachedThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $body->read(10);
+ }
+
+ public function testWriteAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ while (feof($this->stream) === false) {
+ fread($this->stream, 1024);
+ }
+ $body->write('foo');
+
+ $this->assertEquals($this->text . 'foo', (string) $body);
+ }
+
+ public function testWriteDetachedThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $body->write('foo');
+ }
+
+ public function testGetContentsAttached()
+ {
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ fseek($this->stream, 10);
+
+ $this->assertEquals(substr($this->text, 10), $body->getContents());
+ }
+
+ public function testGetContentsDetachedThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->stream = $this->resourceFactory();
+ $body = new Stream($this->stream);
+ $body->detach();
+
+ $body->getContents();
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/CookiesTest.php b/api_candidatos/vendor/slim/psr7/tests/CookiesTest.php
new file mode 100644
index 0000000..8a1cc86
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/CookiesTest.php
@@ -0,0 +1,283 @@
+ 'Works',
+ ]);
+ $prop = new ReflectionProperty($cookies, 'requestCookies');
+ $prop->setAccessible(true);
+ $this->assertNotEmpty($prop->getValue($cookies)['test']);
+ $this->assertEquals('Works', $prop->getValue($cookies)['test']);
+ }
+
+ public function testSetDefaults()
+ {
+ $defaults = [
+ 'value' => 'toast',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => true,
+ 'httponly' => true,
+ 'samesite' => null
+ ];
+
+ $cookies = new Cookies();
+
+ $prop = new ReflectionProperty($cookies, 'defaults');
+ $prop->setAccessible(true);
+
+ $origDefaults = $prop->getValue($cookies);
+
+ $cookies->setDefaults($defaults);
+
+ $this->assertEquals($defaults, $prop->getValue($cookies));
+ $this->assertNotEquals($origDefaults, $prop->getValue($cookies));
+ }
+
+ public function testSetCookieValues()
+ {
+ $cookies = new Cookies();
+ $cookies->set('foo', 'bar');
+
+ $prop = new ReflectionProperty($cookies, 'responseCookies');
+ $prop->setAccessible(true);
+
+ $expectedValue = [
+ 'foo' => [
+ 'value' => 'bar',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => false,
+ 'httponly' => false,
+ 'samesite' => null
+ ]
+ ];
+
+ $this->assertEquals($expectedValue, $prop->getValue($cookies));
+ }
+
+ public function testSetCookieValuesContainDefaults()
+ {
+ $cookies = new Cookies();
+ $defaults = [
+ 'value' => 'toast',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => true,
+ 'httponly' => true,
+ 'samesite' => 'lax'
+ ];
+
+ $cookies->setDefaults($defaults);
+ $cookies->set('foo', 'bar');
+
+ $prop = new ReflectionProperty($cookies, 'responseCookies');
+ $prop->setAccessible(true);
+
+ $expectedValue = [
+ 'foo' => [
+ 'value' => 'bar',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => true,
+ 'httponly' => true,
+ 'samesite' => 'lax'
+ ]
+ ];
+
+ $this->assertEquals($expectedValue, $prop->getValue($cookies));
+ }
+
+ public function testSetCookieValuesCanOverrideDefaults()
+ {
+ $cookies = new Cookies();
+ $defaults = [
+ 'value' => 'toast',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => true,
+ 'httponly' => true,
+ 'samesite' => 'lax'
+ ];
+
+ $cookies->setDefaults($defaults);
+ $cookies->set('foo', ['value' => 'bar', 'secure' => false, 'samesite' => 'strict']);
+
+ $prop = new ReflectionProperty($cookies, 'responseCookies');
+ $prop->setAccessible(true);
+
+ $expectedValue = [
+ 'foo' => [
+ 'value' => 'bar',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => false,
+ 'httponly' => true,
+ 'samesite' => 'strict'
+ ]
+ ];
+
+ $this->assertEquals($expectedValue, $prop->getValue($cookies));
+ }
+
+ public function testSetSameSiteCookieValuesAreCaseInsensitive()
+ {
+ $cookies = new Cookies();
+ $defaults = [
+ 'value' => 'bacon',
+ 'samesite' => 'lax'
+ ];
+
+ $cookies->setDefaults($defaults);
+ $cookies->set('breakfast', ['samesite' => 'StricT']);
+
+ $prop = new ReflectionProperty($cookies, 'responseCookies');
+ $prop->setAccessible(true);
+
+ $expectedValue = [
+ 'breakfast' => [
+ 'value' => 'bacon',
+ 'domain' => null,
+ 'hostonly' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => false,
+ 'httponly' => false,
+ 'samesite' => 'StricT',
+ ]
+ ];
+
+ $this->assertEquals($expectedValue, $prop->getValue($cookies));
+ }
+
+ public function testGet()
+ {
+ $cookies = new Cookies(['foo' => 'bar', 'baz' => null]);
+ $this->assertEquals('bar', $cookies->get('foo'));
+ $this->assertNull($cookies->get('baz', 'defaultValue'));
+ $this->assertNull($cookies->get('missing'));
+ $this->assertEquals('defaultValue', $cookies->get('missing', 'defaultValue'));
+ }
+
+ public function testParseHeader()
+ {
+ $cookies = Cookies::parseHeader('foo=bar; name=Josh');
+ $this->assertEquals('bar', $cookies['foo']);
+ $this->assertEquals('Josh', $cookies['name']);
+ }
+
+ public function testParseHeaderWithJsonArray()
+ {
+ $cookies = Cookies::parseHeader('foo=bar; testarray=["someVar1","someVar2","someVar3"]');
+ $this->assertEquals('bar', $cookies['foo']);
+ $this->assertContains('someVar3', json_decode($cookies['testarray']));
+ }
+
+ public function testToHeaders()
+ {
+ $cookies = new Cookies();
+ $cookies->set('test', 'Works');
+ $cookies->set('test_array', ['value' => 'bar', 'domain' => 'example.com']);
+ $this->assertEquals('test=Works', $cookies->toHeaders()[0]);
+ $this->assertEquals('test_array=bar; domain=example.com', $cookies->toHeaders()[1]);
+ }
+
+ public function testToHeader()
+ {
+ $cookies = new Cookies();
+ $class = new ReflectionClass($cookies);
+ $method = $class->getMethod('toHeader');
+ $method->setAccessible(true);
+ $properties = [
+ 'name' => 'test',
+ 'properties' => [
+ 'value' => 'Works'
+ ]
+ ];
+ $time = time();
+ $formattedDate = gmdate('D, d-M-Y H:i:s e', $time);
+ $propertiesComplex = [
+ 'name' => 'test_complex',
+ 'properties' => [
+ 'value' => 'Works',
+ 'domain' => 'example.com',
+ 'expires' => $time,
+ 'path' => '/',
+ 'secure' => true,
+ 'hostonly' => true,
+ 'httponly' => true,
+ 'samesite' => 'lax'
+ ]
+ ];
+ $stringDate = '2016-01-01 12:00:00';
+ $formattedStringDate = gmdate('D, d-M-Y H:i:s e', strtotime($stringDate));
+ $propertiesStringDate = [
+ 'name' => 'test_date',
+ 'properties' => [
+ 'value' => 'Works',
+ 'expires' => $stringDate,
+ ]
+ ];
+ $cookie = $method->invokeArgs($cookies, $properties);
+ $cookieComplex = $method->invokeArgs($cookies, $propertiesComplex);
+ $cookieStringDate = $method->invokeArgs($cookies, $propertiesStringDate);
+ $this->assertEquals('test=Works', $cookie);
+ $this->assertEquals(
+ 'test_complex=Works; domain=example.com; path=/; expires='
+ . $formattedDate . '; secure; HostOnly; HttpOnly; SameSite=lax',
+ $cookieComplex
+ );
+ $this->assertEquals('test_date=Works; expires=' . $formattedStringDate, $cookieStringDate);
+ }
+
+ public function testParseHeaderException()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ Cookies::parseHeader(new stdClass());
+ }
+
+ public function testSetSameSiteNoneToHeaders()
+ {
+ $cookies = new Cookies();
+ $cookies->set('foo', ['value' => 'bar', 'samesite' => 'None']);
+ $this->assertEquals('foo=bar; SameSite=None', $cookies->toHeaders()[0]);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/EnvironmentTest.php b/api_candidatos/vendor/slim/psr7/tests/EnvironmentTest.php
new file mode 100644
index 0000000..ba32e18
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/EnvironmentTest.php
@@ -0,0 +1,48 @@
+ '/foo/bar/index.php',
+ 'REQUEST_URI' => '/foo/bar?abc=123',
+ ]);
+
+ $this->assertEquals('/foo/bar/index.php', $env['SCRIPT_NAME']);
+ $this->assertEquals('/foo/bar?abc=123', $env['REQUEST_URI']);
+ }
+
+ public function testMockHttps()
+ {
+ $env = Environment::mock([
+ 'HTTPS' => 'on'
+ ]);
+
+ $this->assertEquals('on', $env['HTTPS']);
+ $this->assertEquals(443, $env['SERVER_PORT']);
+ }
+
+ public function testMockRequestScheme()
+ {
+ $env = Environment::mock([
+ 'REQUEST_SCHEME' => 'https'
+ ]);
+
+ $this->assertEquals('https', $env['REQUEST_SCHEME']);
+ $this->assertEquals(443, $env['SERVER_PORT']);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Factory/RequestFactoryTest.php b/api_candidatos/vendor/slim/psr7/tests/Factory/RequestFactoryTest.php
new file mode 100644
index 0000000..02f16e5
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Factory/RequestFactoryTest.php
@@ -0,0 +1,42 @@
+createUri($uri);
+ }
+
+ public function testCreateRequestThrowsExceptionWithInvalidUri()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Parameter 2 of RequestFactory::createRequest() must be a string' .
+ ' or a compatible UriInterface.');
+
+ $factory = $this->createRequestFactory();
+
+ $factory->createRequest('GET', new stdClass());
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Factory/ResponseFactoryTest.php b/api_candidatos/vendor/slim/psr7/tests/Factory/ResponseFactoryTest.php
new file mode 100644
index 0000000..7dc557a
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Factory/ResponseFactoryTest.php
@@ -0,0 +1,42 @@
+assertInstanceOf(ResponseInterface::class, $response);
+ $this->assertSame($code, $response->getStatusCode());
+ $this->assertSame($reasonPhrase, $response->getReasonPhrase());
+ }
+
+ /**
+ * @dataProvider dataCodes
+ *
+ * @param int $code
+ */
+ public function testCreateResponseWithReasonPhrase(int $code)
+ {
+ $response = $this->factory->createResponse($code, 'Reason');
+ $this->assertResponse($response, $code);
+ $this->assertResponseCodeAndReasonPhrase($response, $code, 'Reason');
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Factory/ServerRequestFactoryTest.php b/api_candidatos/vendor/slim/psr7/tests/Factory/ServerRequestFactoryTest.php
new file mode 100644
index 0000000..d46be55
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Factory/ServerRequestFactoryTest.php
@@ -0,0 +1,208 @@
+createUri($uri);
+ }
+
+ public function testGetProtocolVersion()
+ {
+ $env = Environment::mock(['SERVER_PROTOCOL' => 'HTTP/1.0']);
+ $request = $this->createServerRequestFactory()->createServerRequest('GET', '', $env);
+
+ $this->assertEquals('1.0', $request->getProtocolVersion());
+ }
+
+ public function testCreateFromGlobals()
+ {
+ $GLOBALS['getallheaders_return'] = [
+ 'ACCEPT' => 'application/json',
+ 'ACCEPT-CHARSET' => 'utf-8',
+ 'ACCEPT-LANGUAGE' => 'en-US',
+ 'CONTENT-TYPE' => 'multipart/form-data',
+ 'HOST' => 'example.com',
+ 'USER-AGENT' => 'Slim Framework',
+ ];
+
+ $_SERVER = Environment::mock([
+ 'HTTP_HOST' => 'example.com',
+ 'PHP_AUTH_PW' => 'sekrit',
+ 'PHP_AUTH_USER' => 'josh',
+ 'QUERY_STRING' => 'abc=123',
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'REQUEST_METHOD' => 'GET',
+ 'REQUEST_TIME' => time(),
+ 'REQUEST_TIME_FLOAT' => microtime(true),
+ 'REQUEST_URI' => '/foo/bar',
+ 'SCRIPT_NAME' => '/index.php',
+ 'SERVER_NAME' => 'localhost',
+ 'SERVER_PORT' => 8080,
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ ]);
+
+ $request = ServerRequestFactory::createFromGlobals();
+
+ unset($GLOBALS['getallheaders_return']);
+
+ $this->assertEquals('GET', $request->getMethod());
+ $this->assertEquals('1.1', $request->getProtocolVersion());
+
+ $this->assertEquals('application/json', $request->getHeaderLine('Accept'));
+ $this->assertEquals('utf-8', $request->getHeaderLine('Accept-Charset'));
+ $this->assertEquals('en-US', $request->getHeaderLine('Accept-Language'));
+ $this->assertEquals('multipart/form-data', $request->getHeaderLine('Content-Type'));
+
+ $uri = $request->getUri();
+ $this->assertEquals('josh:sekrit', $uri->getUserInfo());
+ $this->assertEquals('example.com', $uri->getHost());
+ $this->assertEquals('8080', $uri->getPort());
+ $this->assertEquals('/foo/bar', $uri->getPath());
+ $this->assertEquals('abc=123', $uri->getQuery());
+ $this->assertEquals('', $uri->getFragment());
+ }
+
+ public function testCreateFromGlobalsWithParsedBody()
+ {
+ $_SERVER = Environment::mock([
+ 'HTTP_CONTENT_TYPE' => 'multipart/form-data',
+ 'REQUEST_METHOD' => 'POST',
+ ]);
+
+ $_POST = [
+ 'def' => '456',
+ ];
+
+ $request = ServerRequestFactory::createFromGlobals();
+
+ // $_POST should be placed into the parsed body
+ $this->assertEquals($_POST, $request->getParsedBody());
+ }
+
+ public function testCreateFromGlobalsBodyPointsToPhpInput()
+ {
+ $request = ServerRequestFactory::createFromGlobals();
+
+ $this->assertEquals('php://input', $request->getBody()->getMetadata('uri'));
+ }
+
+ public function testCreateFromGlobalsSetsACache()
+ {
+ $request = ServerRequestFactory::createFromGlobals();
+
+ // ensure that the Stream's $cache property has been set for this php://input stream
+ $stream = $request->getBody();
+ $class = new ReflectionClass($stream);
+ $property = $class->getProperty('cache');
+ $property->setAccessible(true);
+ $cacheStreamValue = $property->getValue($stream);
+ $this->assertNotNull($cacheStreamValue);
+ }
+
+ public function testCreateFromGlobalsWithUploadedFiles()
+ {
+ $_SERVER = Environment::mock([
+ 'HTTP_CONTENT_TYPE' => 'multipart/form-data',
+ 'REQUEST_METHOD' => 'POST',
+ ]);
+
+ $_FILES = [
+ 'uploaded_file' => [
+ 'name' => [
+ 0 => 'foo.jpg',
+ 1 => 'bar.jpg',
+ ],
+
+ 'type' => [
+ 0 => 'image/jpeg',
+ 1 => 'image/jpeg',
+ ],
+
+ 'tmp_name' => [
+ 0 => '/tmp/phpUA3XUw',
+ 1 => '/tmp/phpXUFS0x',
+ ],
+
+ 'error' => [
+ 0 => 0,
+ 1 => 0,
+ ],
+
+ 'size' => [
+ 0 => 358708,
+ 1 => 236162,
+ ],
+ ]
+ ];
+
+ $request = ServerRequestFactory::createFromGlobals();
+
+ // $_FILES should be mapped to an array of UploadedFile objects
+ $uploadedFiles = $request->getUploadedFiles();
+ $this->assertCount(1, $uploadedFiles);
+ $this->assertArrayHasKey('uploaded_file', $uploadedFiles);
+ $this->assertInstanceOf(UploadedFile::class, $uploadedFiles['uploaded_file'][0]);
+ $this->assertInstanceOf(UploadedFile::class, $uploadedFiles['uploaded_file'][1]);
+ }
+
+ public function testCreateFromGlobalsParsesBodyWithFragmentedContentType()
+ {
+ $_SERVER = Environment::mock([
+ 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded;charset=utf-8',
+ 'REQUEST_METHOD' => 'POST',
+ ]);
+
+ $_POST = [
+ 'def' => '456',
+ ];
+
+ $request = ServerRequestFactory::createFromGlobals();
+
+ $this->assertEquals($_POST, $request->getParsedBody());
+ }
+
+ public function testCreateServerRequestWithNullAsUri()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $env = Environment::mock();
+ $this->createServerRequestFactory()->createServerRequest('GET', null, $env);
+ }
+
+ public function testCreateServerRequestWithInvalidUriObject()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $env = Environment::mock();
+ $this->createServerRequestFactory()->createServerRequest('GET', new stdClass(), $env);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Factory/StreamFactoryTest.php b/api_candidatos/vendor/slim/psr7/tests/Factory/StreamFactoryTest.php
new file mode 100644
index 0000000..e10d38d
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Factory/StreamFactoryTest.php
@@ -0,0 +1,66 @@
+expectException(RuntimeException::class);
+ $this->expectExceptionMessage('StreamFactory::createStream() could not open temporary file stream.');
+
+ $GLOBALS['fopen_return'] = false;
+
+ $factory = $this->createStreamFactory();
+
+ $factory->createStream();
+ }
+
+ public function testCreateStreamFromFileThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('StreamFactory::createStreamFromFile() could not create resource'
+ . ' from file `non-readable`');
+
+ $GLOBALS['fopen_return'] = false;
+
+ $factory = $this->createStreamFactory();
+
+ $factory->createStreamFromFile('non-readable');
+ }
+
+ public function testCreateStreamFromResourceThrowsRuntimeException()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Parameter 1 of StreamFactory::createStreamFromResource() must be a resource.');
+
+ $factory = $this->createStreamFactory();
+
+ $factory->createStreamFromResource('not-resource');
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Factory/UploadedFileFactoryTest.php b/api_candidatos/vendor/slim/psr7/tests/Factory/UploadedFileFactoryTest.php
new file mode 100644
index 0000000..1f46b79
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Factory/UploadedFileFactoryTest.php
@@ -0,0 +1,114 @@
+createStreamFromResource($resource);
+ }
+
+ /**
+ * Prophesize a `\Psr\Http\Message\StreamInterface` with a `getMetadata` method prophecy.
+ *
+ * @param string $argKey Argument for the method prophecy.
+ * @param mixed $returnValue Return value of the `getMetadata` method.
+ *
+ * @return StreamInterface
+ */
+ protected function prophesizeStreamInterfaceWithGetMetadataMethod(string $argKey, $returnValue): StreamInterface
+ {
+ $streamProphecy = $this->prophesize(StreamInterface::class);
+
+ /** @noinspection PhpUndefinedMethodInspection */
+ $streamProphecy
+ ->getMetadata($argKey)
+ ->willReturn($returnValue)
+ ->shouldBeCalled();
+
+ /** @var StreamInterface $stream */
+ $stream = $streamProphecy->reveal();
+
+ return $stream;
+ }
+
+ public function testCreateUploadedFileWithInvalidUri()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('File is not readable.');
+
+ // Prophesize a `\Psr\Http\Message\StreamInterface` with a `getMetadata` method prophecy.
+ $streamProphecy = $this->prophesize(StreamInterface::class);
+
+ /** @noinspection PhpUndefinedMethodInspection */
+ $streamProphecy
+ ->getMetadata('uri')
+ ->willReturn(null)
+ ->shouldBeCalled();
+
+ /** @var StreamInterface $stream */
+ $stream = $streamProphecy->reveal();
+
+ $this->factory->createUploadedFile($stream);
+ }
+
+ public function testCreateUploadedFileWithNonReadableFile()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('File is not readable.');
+
+ // Prophesize a `\Psr\Http\Message\StreamInterface` with a `getMetadata` and `isReadable` method prophecies.
+ $streamProphecy = $this->prophesize(StreamInterface::class);
+
+ /** @noinspection PhpUndefinedMethodInspection */
+ $streamProphecy
+ ->getMetadata('uri')
+ ->willReturn('non-readable')
+ ->shouldBeCalled();
+
+ /** @noinspection PhpUndefinedMethodInspection */
+ $streamProphecy
+ ->isReadable()
+ ->willReturn(false)
+ ->shouldBeCalled();
+
+ /** @var StreamInterface $stream */
+ $stream = $streamProphecy->reveal();
+
+ $this->factory->createUploadedFile($stream);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Factory/UriFactoryTest.php b/api_candidatos/vendor/slim/psr7/tests/Factory/UriFactoryTest.php
new file mode 100644
index 0000000..1927569
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Factory/UriFactoryTest.php
@@ -0,0 +1,243 @@
+createUriFactory()->createUri('https://josh@example.com/foo/bar?abc=123#section3');
+
+ $this->assertEquals('josh@example.com', $uri->getAuthority());
+ }
+
+ public function testGetAuthority()
+ {
+ $uri = $this->createUriFactory()->createUri('https://example.com/foo/bar?abc=123#section3');
+
+ $this->assertEquals('example.com', $uri->getAuthority());
+ }
+
+ public function testGetAuthorityWithNonStandardPort()
+ {
+ $uri = $this->createUriFactory()->createUri('https://example.com:400/foo/bar?abc=123#section3');
+
+ $this->assertEquals('example.com:400', $uri->getAuthority());
+ }
+
+ public function testGetUserInfoWithUsernameAndPassword()
+ {
+ $uri = $this->createUriFactory()->createUri('https://josh:sekrit@example.com:443/foo/bar?abc=123#section3');
+
+ $this->assertEquals('josh:sekrit', $uri->getUserInfo());
+ }
+
+ public function testGetUserInfoWithUsernameAndPasswordEncodesCorrectly()
+ {
+ $uri = $this
+ ->createUriFactory()
+ ->createUri('https://bob@example.com:pass:word@example.com:443/foo/bar?abc=123#section3');
+
+ $this->assertEquals('bob%40example.com:pass%3Aword', $uri->getUserInfo());
+ }
+
+ public function testGetUserInfoWithUsername()
+ {
+ $uri = $this->createUriFactory()->createUri('http://josh@example.com/foo/bar?abc=123#section3');
+
+ $this->assertEquals('josh', $uri->getUserInfo());
+ }
+
+ public function testGetUserInfoNone()
+ {
+ $uri = $this->createUriFactory()->createUri('https://example.com/foo/bar?abc=123#section3');
+
+ $this->assertEquals('', $uri->getUserInfo());
+ }
+
+ public function testCreateFromString()
+ {
+ $uri = $this->createUriFactory()->createUri('https://example.com:8080/foo/bar?abc=123');
+
+ $this->assertEquals('https', $uri->getScheme());
+ $this->assertEquals('example.com', $uri->getHost());
+ $this->assertEquals('8080', $uri->getPort());
+ $this->assertEquals('/foo/bar', $uri->getPath());
+ $this->assertEquals('abc=123', $uri->getQuery());
+ }
+
+ public function testCreateFromGlobals()
+ {
+ $globals = Environment::mock([
+ 'SCRIPT_NAME' => '/index.php',
+ 'REQUEST_URI' => '/foo/bar?baz=1',
+ 'PHP_AUTH_USER' => 'josh',
+ 'PHP_AUTH_PW' => 'sekrit',
+ 'QUERY_STRING' => 'abc=123',
+ 'HTTP_HOST' => 'example.com:8080',
+ 'SERVER_PORT' => 8080,
+ ]);
+
+ $uri = $this->createUriFactory()->createFromGlobals($globals);
+
+ $this->assertEquals('josh:sekrit', $uri->getUserInfo());
+ $this->assertEquals('example.com', $uri->getHost());
+ $this->assertEquals('8080', $uri->getPort());
+ $this->assertEquals('/foo/bar', $uri->getPath());
+ $this->assertEquals('abc=123', $uri->getQuery());
+ $this->assertEquals('', $uri->getFragment());
+ }
+
+ public function testCreateFromGlobalsWithHttps()
+ {
+ $globals = Environment::mock(
+ [
+ 'HTTPS' => 'on',
+ 'HTTP_HOST' => 'example.com'
+ ]
+ );
+
+ // Make the 'SERVER_PORT' empty as we want to test if the default server port gets set correctly.
+ $globals['SERVER_PORT'] = '';
+
+ $uri = $this->createUriFactory()->createFromGlobals($globals);
+
+ $this->assertEquals('https', $uri->getScheme());
+ $this->assertEquals('example.com', $uri->getHost());
+
+ // The port is expected to be NULL as the server port is the default standard (443 in case of https).
+ $this->assertNull($uri->getPort());
+ }
+
+ public function testCreateFromGlobalsUsesServerNameAsHostIfHostHeaderIsNotPresent()
+ {
+ $globals = Environment::mock([
+ 'SERVER_NAME' => 'example.com',
+ ]);
+
+ $uri = $this->createUriFactory()->createFromGlobals($globals);
+
+ $this->assertEquals('example.com', $uri->getHost());
+ }
+
+ public function testCreateFromGlobalWithIPv6HostNoPort()
+ {
+ $environment = Environment::mock([
+ 'SCRIPT_NAME' => '/index.php',
+ 'REQUEST_URI' => '/foo/bar',
+ 'PHP_AUTH_USER' => 'josh',
+ 'PHP_AUTH_PW' => 'sekrit',
+ 'QUERY_STRING' => 'abc=123',
+ 'HTTP_HOST' => '[2001:db8::1]',
+ 'REMOTE_ADDR' => '2001:db8::1',
+ 'SERVER_PORT' => 8080,
+ ]);
+ $uri = $this->createUriFactory()->createFromGlobals($environment);
+
+ $this->assertEquals('josh:sekrit', $uri->getUserInfo());
+ $this->assertEquals('[2001:db8::1]', $uri->getHost());
+ $this->assertEquals('8080', $uri->getPort());
+ $this->assertEquals('/foo/bar', $uri->getPath());
+ $this->assertEquals('abc=123', $uri->getQuery());
+ $this->assertEquals('', $uri->getFragment());
+ }
+
+ public function testCreateFromGlobalsWithIPv6HostWithPort()
+ {
+ $globals = Environment::mock([
+ 'SCRIPT_NAME' => '/index.php',
+ 'REQUEST_URI' => '/foo/bar',
+ 'PHP_AUTH_USER' => 'josh',
+ 'PHP_AUTH_PW' => 'sekrit',
+ 'QUERY_STRING' => 'abc=123',
+ 'HTTP_HOST' => '[2001:db8::1]:8080',
+ 'REMOTE_ADDR' => '2001:db8::1',
+ 'SERVER_PORT' => 8080,
+ ]);
+
+ $uri = $this->createUriFactory()->createFromGlobals($globals);
+
+ $this->assertEquals('josh:sekrit', $uri->getUserInfo());
+ $this->assertEquals('[2001:db8::1]', $uri->getHost());
+ $this->assertEquals('8080', $uri->getPort());
+ $this->assertEquals('/foo/bar', $uri->getPath());
+ $this->assertEquals('abc=123', $uri->getQuery());
+ $this->assertEquals('', $uri->getFragment());
+ }
+
+ public function testCreateFromGlobalsWithBasePathContainingSpace()
+ {
+ $globals = Environment::mock([
+ 'SCRIPT_NAME' => "/f'oo bar/index.php",
+ 'REQUEST_URI' => "/f%27oo%20bar/baz",
+ ]);
+ $uri = $this->createUriFactory()->createFromGlobals($globals);
+
+ $this->assertEquals('/f%27oo%20bar/baz', $uri->getPath());
+ }
+
+ public function testWithPathWhenBaseRootIsEmpty()
+ {
+ $globals = Environment::mock([
+ 'SCRIPT_NAME' => '/index.php',
+ 'REQUEST_URI' => '/bar',
+ ]);
+ $uri = $this->createUriFactory()->createFromGlobals($globals);
+
+ $this->assertEquals('http://localhost/test', (string) $uri->withPath('test'));
+ }
+
+ /**
+ * When the URL is /foo/index.php/bar/baz, we need the baseURL to be
+ * /foo/index.php so that routing works correctly.
+ *
+ * @ticket 1639 as a fix to 1590 broke this.
+ */
+ public function testRequestURIContainsIndexDotPhp()
+ {
+ $uri = $this->createUriFactory()->createFromGlobals(
+ Environment::mock(
+ [
+ 'SCRIPT_NAME' => '/foo/index.php',
+ 'REQUEST_URI' => '/foo/index.php/bar/baz',
+ ]
+ )
+ );
+ $this->assertSame('/foo/index.php/bar/baz', $uri->getPath());
+ }
+
+ public function testRequestURICanContainParams()
+ {
+ $uri = $this->createUriFactory()->createFromGlobals(
+ Environment::mock(
+ [
+ 'REQUEST_URI' => '/foo?abc=123',
+ ]
+ )
+ );
+ $this->assertEquals('abc=123', $uri->getQuery());
+ }
+
+ public function testUriDistinguishZeroFromEmptyString()
+ {
+ $expected = 'https://0:0@0:1/0?0#0';
+ $this->assertSame($expected, (string) $this->createUriFactory()->createUri($expected));
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/HeaderTest.php b/api_candidatos/vendor/slim/psr7/tests/HeaderTest.php
new file mode 100644
index 0000000..d062768
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/HeaderTest.php
@@ -0,0 +1,61 @@
+headerFactory();
+ $this->assertEquals('ACCEPT', $header->getOriginalName());
+ }
+
+ public function testGetNormalizedName(): void
+ {
+ $header = $this->headerFactory();
+ $this->assertEquals('accept', $header->getNormalizedName());
+ }
+
+ public function testAddValue(): void
+ {
+ $header = $this->headerFactory();
+ $header2 = $header->addValue('text/html');
+
+ $this->assertEquals(['application/json', 'text/html'], $header->getValues());
+ $this->assertSame($header2, $header);
+ }
+
+ public function testAddValuesString(): void
+ {
+ $header = $this->headerFactory();
+ $header2 = $header->addValues('text/html');
+
+ $this->assertEquals(['application/json', 'text/html'], $header->getValues());
+ $this->assertSame($header2, $header);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/HeadersTest.php b/api_candidatos/vendor/slim/psr7/tests/HeadersTest.php
new file mode 100644
index 0000000..0642058
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/HeadersTest.php
@@ -0,0 +1,288 @@
+ 'application/json',
+ ];
+
+ $headers = Headers::createFromGlobals();
+
+ unset($GLOBALS['getallheaders_return']);
+
+ $this->assertEquals(['accept' => ['application/json']], $headers->getHeaders());
+ $this->assertEquals(['ACCEPT' => ['application/json']], $headers->getHeaders(true));
+ }
+
+ public function testCreateFromGlobalsUsesEmptyArrayIfGetAllHeadersReturnsFalse()
+ {
+ $GLOBALS['getallheaders_return'] = false;
+
+ $headers = Headers::createFromGlobals();
+
+ unset($GLOBALS['getallheaders_return']);
+
+ $this->assertEquals([], $headers->getHeaders());
+ }
+
+ public function testAddHeader()
+ {
+ $headers = new Headers([
+ 'Accept' => 'application/json',
+ ]);
+
+ $headers->addHeader('Accept', 'text/html');
+
+ $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('Accept'));
+ $this->assertEquals(['accept' => ['application/json', 'text/html']], $headers->getHeaders());
+ $this->assertEquals(['Accept' => ['application/json', 'text/html']], $headers->getHeaders(true));
+ }
+
+ public function testAddHeaderValueEmptyArray()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $headers = new Headers();
+ $headers->addHeader('Header', []);
+ }
+
+ public function testRemoveHeader()
+ {
+ $headers = new Headers([
+ 'Accept' => 'application/json',
+ ]);
+
+ $headers->removeHeader('Accept');
+
+ $this->assertEquals([], $headers->getHeader('Accept'));
+ $this->assertEquals([], $headers->getHeaders());
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function testRemoveHeaderByIncompatibleStringWithRFC()
+ {
+ $headers = new Headers();
+ $headers->removeHeader('');
+ }
+
+ public function testGetHeader()
+ {
+ $headers = new Headers([
+ 'Accept' => ['application/json', 'text/html'],
+ ]);
+
+ $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('accept'));
+ $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('Accept'));
+ $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('HTTP_ACCEPT'));
+ }
+
+ public function testGetHeaderReturnsValidatedAndTrimedHeaderDefaultValue()
+ {
+ $headers = new Headers([]);
+
+ $this->assertEquals(['application/json'], $headers->getHeader('accept', ' application/json'));
+ }
+
+ public function testGetHeaderThrowsExceptionWithInvalidDefaultArgument()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $headers = new Headers([]);
+
+ $headers->getHeader('accept', new stdClass());
+ }
+
+ public function testSetHeader()
+ {
+ $headers = new Headers([
+ 'Content-Length' => 0,
+ ]);
+
+ $headers->setHeader('Content-Length', 100);
+
+ $this->assertSame(['100'], $headers->getHeader('Content-Length'));
+ $this->assertEquals(['content-length' => ['100']], $headers->getHeaders());
+ $this->assertEquals(['Content-Length' => ['100']], $headers->getHeaders(true));
+ }
+
+ public function testSetHeaderPreservesOriginalCaseIfHeaderAlreadyExists()
+ {
+ $headers = new Headers([
+ 'CONTENT-LENGTH' => 0,
+ ]);
+
+ $headers->setHeader('Content-Length', 100);
+
+ $this->assertEquals(['content-length' => ['100']], $headers->getHeaders());
+ $this->assertEquals(['CONTENT-LENGTH' => ['100']], $headers->getHeaders(true));
+ }
+
+ public function testSetHeaders()
+ {
+ $headers = new Headers([
+ 'Content-Length' => 0,
+ ]);
+
+ $headers->setHeaders([
+ 'Accept' => 'application/json',
+ ]);
+
+ $this->assertEquals(['accept' => ['application/json']], $headers->getHeaders());
+ $this->assertEquals(['Accept' => ['application/json']], $headers->getHeaders(true));
+ }
+
+ public function testHasHeader()
+ {
+ $headers = new Headers([
+ 'Accept' => 'application/json',
+ ]);
+
+ $this->assertTrue($headers->hasHeader('accept'));
+ $this->assertTrue($headers->hasHeader('Accept'));
+ $this->assertTrue($headers->hasHeader('HTTP_ACCEPT'));
+ }
+
+ public function testGetHeaders()
+ {
+ $headers = new Headers([
+ 'HTTP_ACCEPT' => 'text/html',
+ 'HTTP_CONTENT_TYPE' => 'application/json',
+ ]);
+
+ $expectedNormalizedHeaders = [
+ 'accept' => ['text/html'],
+ 'content-type' => ['application/json'],
+ ];
+
+ $this->assertEquals($expectedNormalizedHeaders, $headers->getHeaders());
+ }
+
+ public function testGetHeadersPreservesOriginalCase()
+ {
+ $headers = new Headers([
+ 'HTTP_ACCEPT' => 'text/html',
+ 'HTTP_CONTENT_TYPE' => 'application/json',
+ ]);
+
+ $expectedOriginalHeaders = [
+ 'ACCEPT' => ['text/html'],
+ 'CONTENT-TYPE' => ['application/json'],
+ ];
+
+ $this->assertEquals($expectedOriginalHeaders, $headers->getHeaders(true));
+ }
+
+ public function testParseAuthorizationHeader()
+ {
+ $expectedValue = 'Basic ' . base64_encode('user:password');
+
+ $headers = new Headers(['Authorization' => $expectedValue]);
+ $this->assertEquals([$expectedValue], $headers->getHeader('Authorization'));
+
+ $headers = new Headers([], ['REDIRECT_HTTP_AUTHORIZATION' => 'cookie']);
+ $this->assertEquals(['cookie'], $headers->getHeader('Authorization'));
+
+ $headers = new Headers([], ['PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password']);
+ $this->assertEquals([$expectedValue], $headers->getHeader('Authorization'));
+
+ $headers = new Headers([], ['PHP_AUTH_DIGEST' => 'digest']);
+ $this->assertEquals(['digest'], $headers->getHeader('Authorization'));
+ }
+
+ /**
+ * @dataProvider provideInvalidHeaderNames
+ */
+ public function testWithInvalidHeaderName($headerName): void
+ {
+ $headers = new Headers();
+
+ $this->expectException(\InvalidArgumentException::class);
+
+ $headers->setHeader($headerName, 'foo');
+ }
+
+ public static function provideInvalidHeaderNames(): array
+ {
+ return [
+ [[]],
+ [false],
+ [new \stdClass()],
+ ["Content-Type\r\n\r\n"],
+ ["Content-Type\r\n"],
+ ["Content-Type\n"],
+ ["\r\nContent-Type"],
+ ["\nContent-Type"],
+ ["\n"],
+ ["\r\n"],
+ ["\t"],
+ ];
+ }
+
+ /**
+ * @dataProvider provideInvalidHeaderValues
+ */
+ public function testSetInvalidHeaderValue($headerValue)
+ {
+ $headers = new Headers();
+
+ $this->expectException(\InvalidArgumentException::class);
+
+ $headers->setHeader('Content-Type', $headerValue);
+ }
+
+ public static function provideInvalidHeaderValues(): array
+ {
+ // Explicit tests for newlines as the most common exploit vector.
+ $tests = [
+ ["new\nline"],
+ ["new\r\nline"],
+ ["new\rline"],
+ ["new\r\n line"],
+ ["newline\n"],
+ ["\nnewline"],
+ ["newline\r\n"],
+ ["\n\rnewline"],
+ ];
+
+ for ($i = 0; $i <= 0xff; $i++) {
+ if (\chr($i) == "\t") {
+ continue;
+ }
+ if (\chr($i) == " ") {
+ continue;
+ }
+ if ($i >= 0x21 && $i <= 0x7e) {
+ continue;
+ }
+ if ($i >= 0x80) {
+ continue;
+ }
+
+ $tests[] = ["foo" . \chr($i) . "bar"];
+ $tests[] = ["foo" . \chr($i)];
+ }
+
+ return $tests;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Integration/BaseTestFactories.php b/api_candidatos/vendor/slim/psr7/tests/Integration/BaseTestFactories.php
new file mode 100644
index 0000000..1aa31d8
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Integration/BaseTestFactories.php
@@ -0,0 +1,57 @@
+createUri($uri);
+ }
+
+ /**
+ * @param $data
+ * @return Stream
+ */
+ protected function buildStream($data): Stream
+ {
+ if (!is_resource($data)) {
+ $h = fopen('php://temp', 'w+');
+ fwrite($h, $data);
+
+ $data = $h;
+ }
+
+ return new Stream($data);
+ }
+
+ /**
+ * @param $data
+ * @return UploadedFile
+ */
+ protected function buildUploadableFile($data): UploadedFile
+ {
+ return new UploadedFile($this->buildStream($data));
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Integration/RequestTest.php b/api_candidatos/vendor/slim/psr7/tests/Integration/RequestTest.php
new file mode 100644
index 0000000..0ea00bc
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Integration/RequestTest.php
@@ -0,0 +1,36 @@
+buildUri('/'),
+ new Headers(),
+ [],
+ [],
+ $this->buildStream('')
+ );
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Integration/ResponseTest.php b/api_candidatos/vendor/slim/psr7/tests/Integration/ResponseTest.php
new file mode 100644
index 0000000..7bd45fe
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Integration/ResponseTest.php
@@ -0,0 +1,27 @@
+buildUri('/'),
+ new Headers(),
+ $_COOKIE,
+ $_SERVER,
+ $this->buildStream('')
+ );
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Integration/StreamTest.php b/api_candidatos/vendor/slim/psr7/tests/Integration/StreamTest.php
new file mode 100644
index 0000000..e70af71
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Integration/StreamTest.php
@@ -0,0 +1,46 @@
+tempFilename = tempnam(sys_get_temp_dir(), 'Slim_Http_UploadedFileTest_');
+ if (!$this->tempFilename) {
+ throw new \RuntimeException("Unable to create temporary file");
+ }
+ file_put_contents($this->tempFilename, '12345');
+
+ return new UploadedFile(
+ $this->tempFilename,
+ basename($this->tempFilename),
+ 'text/plain',
+ (int)filesize($this->tempFilename)
+ );
+ }
+
+ protected function tearDown(): void
+ {
+ if (is_file($this->tempFilename)) {
+ unlink($this->tempFilename);
+ }
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Integration/UriTest.php b/api_candidatos/vendor/slim/psr7/tests/Integration/UriTest.php
new file mode 100644
index 0000000..525052a
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Integration/UriTest.php
@@ -0,0 +1,30 @@
+createUri($uri);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/MessageTest.php b/api_candidatos/vendor/slim/psr7/tests/MessageTest.php
new file mode 100644
index 0000000..eced34f
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/MessageTest.php
@@ -0,0 +1,186 @@
+protocolVersion = '1.0';
+
+ $this->assertEquals('1.0', $message->getProtocolVersion());
+ }
+
+ public function testWithProtocolVersion()
+ {
+ $message = new MessageStub();
+ $clone = $message->withProtocolVersion('1.0');
+
+ $this->assertEquals('1.0', $clone->protocolVersion);
+ }
+
+ public function testWithProtocolVersionInvalidThrowsException()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $message = new MessageStub();
+ $message->withProtocolVersion('3.0');
+ }
+
+ public function testGetHeaders()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+ $headers->addHeader('X-Foo', 'two');
+ $headers->addHeader('X-Foo', 'three');
+
+ $message = new MessageStub();
+ $message->headers = $headers;
+
+ $shouldBe = [
+ 'X-Foo' => [
+ 'one',
+ 'two',
+ 'three',
+ ],
+ ];
+
+ $this->assertEquals($shouldBe, $message->getHeaders());
+ }
+
+ public function testHasHeader()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+
+ $message = new MessageStub();
+ $message->headers = $headers;
+
+ $this->assertTrue($message->hasHeader('X-Foo'));
+ $this->assertFalse($message->hasHeader('X-Bar'));
+ }
+
+ public function testGetHeaderLine()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+ $headers->addHeader('X-Foo', 'two');
+ $headers->addHeader('X-Foo', 'three');
+
+ $message = new MessageStub();
+ $message->headers = $headers;
+
+ $this->assertEquals('one,two,three', $message->getHeaderLine('X-Foo'));
+ $this->assertEquals('', $message->getHeaderLine('X-Bar'));
+ }
+
+ public function testGetHeader()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+ $headers->addHeader('X-Foo', 'two');
+ $headers->addHeader('X-Foo', 'three');
+
+ $message = new MessageStub();
+ $message->headers = $headers;
+
+ $this->assertEquals(['one', 'two', 'three'], $message->getHeader('X-Foo'));
+ $this->assertEquals([], $message->getHeader('X-Bar'));
+ }
+
+ public function testWithHeader()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+ $message = new MessageStub();
+ $message->headers = $headers;
+ $clone = $message->withHeader('X-Foo', 'bar');
+
+ $this->assertEquals('bar', $clone->getHeaderLine('X-Foo'));
+ }
+
+ public function testWithAddedHeader()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+ $message = new MessageStub();
+ $message->headers = $headers;
+ $clone = $message->withAddedHeader('X-Foo', 'two');
+
+ $this->assertEquals('one,two', $clone->getHeaderLine('X-Foo'));
+ }
+
+ public function testWithoutHeader()
+ {
+ $headers = new Headers();
+ $headers->addHeader('X-Foo', 'one');
+ $headers->addHeader('X-Bar', 'two');
+ $response = new MessageStub();
+ $response->headers = $headers;
+ $clone = $response->withoutHeader('X-Foo');
+ $shouldBe = [
+ 'X-Bar' => ['two'],
+ ];
+
+ $this->assertEquals($shouldBe, $clone->getHeaders());
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function testWithoutHeaderByIncompatibleStringWithRFC()
+ {
+ $headers = new Headers();
+ $response = new MessageStub();
+ $response->headers = $headers;
+ $response->withoutHeader('getBody();
+ $message = new MessageStub();
+ $message->body = $body;
+
+ $this->assertSame($body, $message->getBody());
+ }
+
+ public function testWithBody()
+ {
+ $body = $this->getBody();
+ $body2 = $this->getBody();
+ $message = new MessageStub();
+ $message->body = $body;
+ $clone = $message->withBody($body2);
+
+ $this->assertSame($body, $message->body);
+ $this->assertSame($body2, $clone->body);
+ }
+
+ /**
+ * @return MockObject|Stream
+ */
+ protected function getBody()
+ {
+ return $this
+ ->getMockBuilder(Stream::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/Mocks/MessageStub.php b/api_candidatos/vendor/slim/psr7/tests/Mocks/MessageStub.php
new file mode 100644
index 0000000..3672d84
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/Mocks/MessageStub.php
@@ -0,0 +1,37 @@
+detach(), 'Returns null since there is no such underlying stream');
+ self::assertNull($body->getSize(), 'Current size is undefined');
+ self::assertSame(0, $body->tell(), 'Pointer is considered to be at position 0 to conform');
+ self::assertTrue($body->eof(), 'Always considered to be at EOF');
+ self::assertFalse($body->isSeekable(), 'Cannot seek');
+ self::assertTrue($body->isWritable(), 'Body is writable');
+ self::assertFalse($body->isReadable(), 'Body is not readable');
+ self::assertSame('', $body->getContents(), 'Data cannot be retrieved once written');
+ self::assertNull($body->getMetadata(), 'Metadata mechanism is not implemented');
+ }
+
+ public function testWrite()
+ {
+ $ob_initial_level = ob_get_level();
+
+ // Start output buffering.
+ ob_start();
+
+ // Start output buffering again to test the while-loop in the `write()`
+ // method that calls `ob_get_clean()` as long as the ob level is bigger
+ // than 0.
+ ob_start();
+ echo 'buffer content: ';
+
+ // Set the ob level shift that should be applied in the `ob_get_level()`
+ // function override. That way, the `write()` method would only flush
+ // the second ob, not the first one. We will add the initial ob level
+ // because phpunit may have started ob too.
+ $GLOBALS['ob_get_level_shift'] = -($ob_initial_level + 1);
+
+ $body = new NonBufferedBody();
+ $length0 = $body->write('hello ');
+ $length1 = $body->write('world');
+
+ unset($GLOBALS['ob_get_level_shift']);
+ $contents = ob_get_clean();
+
+ $this->assertEquals(strlen('buffer content: ') + strlen('hello '), $length0);
+ $this->assertEquals(strlen('world'), $length1);
+ $this->assertEquals('buffer content: hello world', $contents);
+ }
+
+ public function testWithHeader()
+ {
+ (new Response())
+ ->withBody(new NonBufferedBody())
+ ->withHeader('Foo', 'Bar');
+
+ self::assertSame([
+ [
+ 'header' => 'Foo: Bar',
+ 'replace' => true,
+ 'status_code' => null
+ ]
+ ], HeaderStack::stack());
+ }
+
+ public function testWithAddedHeader()
+ {
+ (new Response())
+ ->withBody(new NonBufferedBody())
+ ->withHeader('Foo', 'Bar')
+ ->withAddedHeader('Foo', 'Baz');
+
+ self::assertSame([
+ [
+ 'header' => 'Foo: Bar',
+ 'replace' => true,
+ 'status_code' => null
+ ],
+ [
+ 'header' => 'Foo: Bar,Baz',
+ 'replace' => true,
+ 'status_code' => null
+ ]
+ ], HeaderStack::stack());
+ }
+
+ public function testWithoutHeader()
+ {
+ (new Response())
+ ->withBody(new NonBufferedBody())
+ ->withHeader('Foo', 'Bar')
+ ->withoutHeader('Foo');
+
+ self::assertSame([], HeaderStack::stack());
+ }
+
+ public function testCloseThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('A NonBufferedBody is not closable.');
+
+ (new NonBufferedBody())->close();
+ }
+
+ public function testSeekThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('A NonBufferedBody is not seekable.');
+
+ (new NonBufferedBody())->seek(10);
+ }
+
+ public function testRewindThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('A NonBufferedBody is not rewindable.');
+
+ (new NonBufferedBody())->rewind();
+ }
+
+ public function testReadThrowsRuntimeException()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('A NonBufferedBody is not readable.');
+
+ (new NonBufferedBody())->read(10);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/RequestTest.php b/api_candidatos/vendor/slim/psr7/tests/RequestTest.php
new file mode 100644
index 0000000..da54f98
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/RequestTest.php
@@ -0,0 +1,458 @@
+createUri('https://example.com:443/foo/bar?abc=123');
+ $headers = Headers::createFromGlobals($env);
+ $cookies = [
+ 'user' => 'john',
+ 'id' => '123',
+ ];
+ $serverParams = $env;
+ $body = (new StreamFactory())->createStream();
+ $uploadedFiles = UploadedFile::createFromGlobals($env);
+ $request = new Request('GET', $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);
+
+ return $request;
+ }
+
+ public function testDisableSetter()
+ {
+ $request = $this->requestFactory();
+ $request->foo = 'bar';
+
+ $this->assertFalse(property_exists($request, 'foo'));
+ }
+
+ public function testAddsHostHeaderFromUri()
+ {
+ $request = $this->requestFactory();
+ $this->assertEquals('example.com', $request->getHeaderLine('Host'));
+ }
+
+ public function testGetMethod()
+ {
+ $this->assertEquals('GET', $this->requestFactory()->getMethod());
+ }
+
+ public function testWithMethod()
+ {
+ $request = $this->requestFactory()->withMethod('PUT');
+
+ $this->assertEquals('PUT', $request->getMethod());
+ }
+
+ public function testWithMethodCaseSensitive()
+ {
+ $request = $this->requestFactory()->withMethod('pOsT');
+
+ $this->assertEquals('pOsT', $request->getMethod());
+ }
+
+ public function testWithAllAllowedCharactersMethod()
+ {
+ $request = $this->requestFactory()->withMethod("!#$%&'*+.^_`|~09AZ-");
+
+ $this->assertEquals("!#$%&'*+.^_`|~09AZ-", $request->getMethod());
+ }
+
+ public function testWithMethodInvalid()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->requestFactory()->withMethod('B@R');
+ }
+
+ public function testCreateRequestWithInvalidMethodString()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $uri = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123');
+ $headers = new Headers();
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+
+ new Request('B@R', $uri, $headers, $cookies, $serverParams, $body);
+ }
+
+ public function testCreateRequestWithInvalidMethodOther()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $uri = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123');
+ $headers = new Headers();
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+
+ new Request(10, $uri, $headers, $cookies, $serverParams, $body);
+ }
+
+ public function testGetRequestTarget()
+ {
+ $this->assertEquals('/foo/bar?abc=123', $this->requestFactory()->getRequestTarget());
+ }
+
+ public function testGetRequestTargetAlreadySet()
+ {
+ $request = $this->requestFactory();
+ $prop = new ReflectionProperty($request, 'requestTarget');
+ $prop->setAccessible(true);
+ $prop->setValue($request, '/foo/bar?abc=123');
+
+ $this->assertEquals('/foo/bar?abc=123', $request->getRequestTarget());
+ }
+
+ public function testGetRequestTargetIfNoUri()
+ {
+ $request = $this->requestFactory();
+ $prop = new ReflectionProperty($request, 'uri');
+ $prop->setAccessible(true);
+ $prop->setValue($request, null);
+
+ $this->assertEquals('/', $request->getRequestTarget());
+ }
+
+ public function testWithRequestTarget()
+ {
+ $clone = $this->requestFactory()->withRequestTarget('/test?user=1');
+
+ $this->assertEquals('/test?user=1', $clone->getRequestTarget());
+ }
+
+ public function testWithRequestTargetThatHasSpaces()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->requestFactory()->withRequestTarget('/test/m ore/stuff?user=1');
+ }
+
+ public function testGetUri()
+ {
+ $uri = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123');
+ $headers = new Headers();
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+ $request = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
+
+ $this->assertSame($uri, $request->getUri());
+ }
+
+ public function testWithUri()
+ {
+ // Uris
+ $uri1 = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123');
+ $uri2 = (new UriFactory())->createUri('https://example2.com:443/test?xyz=123');
+
+ // Request
+ $headers = new Headers();
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+ $request = new Request('GET', $uri1, $headers, $cookies, $serverParams, $body);
+ $clone = $request->withUri($uri2);
+
+ $this->assertSame($uri2, $clone->getUri());
+ }
+
+ public function testWithUriPreservesHost()
+ {
+ // When `$preserveHost` is set to `true`, this method interacts with
+ // the Host header in the following ways:
+
+ // - If the Host header is missing or empty, and the new URI contains
+ // a host component, this method MUST update the Host header in the returned
+ // request.
+ $uri1 = (new UriFactory())->createUri('');
+ $uri2 = (new UriFactory())->createUri('http://example2.com/test');
+
+ // Request
+ $headers = new Headers();
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+ $request = new Request('GET', $uri1, $headers, $cookies, $serverParams, $body);
+
+ $clone = $request->withUri($uri2, true);
+ $this->assertSame('example2.com', $clone->getHeaderLine('Host'));
+
+ // - If the Host header is missing or empty, and the new URI does not contain a
+ // host component, this method MUST NOT update the Host header in the returned
+ // request.
+ $uri3 = (new UriFactory())->createUri('');
+
+ $clone = $request->withUri($uri3, true);
+ $this->assertSame('', $clone->getHeaderLine('Host'));
+
+ // - If a Host header is present and non-empty, this method MUST NOT update
+ // the Host header in the returned request.
+ $request = $request->withHeader('Host', 'example.com');
+ $clone = $request->withUri($uri2, true);
+ $this->assertSame('example.com', $clone->getHeaderLine('Host'));
+ }
+
+ public function testGetCookieParams()
+ {
+ $shouldBe = [
+ 'user' => 'john',
+ 'id' => '123',
+ ];
+
+ $this->assertEquals($shouldBe, $this->requestFactory()->getCookieParams());
+ }
+
+ public function testWithCookieParams()
+ {
+ $request = $this->requestFactory();
+ $clone = $request->withCookieParams(['type' => 'framework']);
+
+ $this->assertEquals(['type' => 'framework'], $clone->getCookieParams());
+ }
+
+ public function testGetQueryParams()
+ {
+ $this->assertEquals(['abc' => '123'], $this->requestFactory()->getQueryParams());
+ }
+
+ public function testGetQueryParamsAlreadySet()
+ {
+ $request = $this->requestFactory();
+ $prop = new ReflectionProperty($request, 'queryParams');
+ $prop->setAccessible(true);
+ $prop->setValue($request, ['foo' => 'bar']);
+
+ $this->assertEquals(['foo' => 'bar'], $request->getQueryParams());
+ }
+
+ public function testWithQueryParams()
+ {
+ $request = $this->requestFactory();
+ $clone = $request->withQueryParams(['foo' => 'bar']);
+ $cloneUri = $clone->getUri();
+
+ $this->assertEquals('abc=123', $cloneUri->getQuery()); // <-- Unchanged
+ $this->assertEquals(['foo' => 'bar'], $clone->getQueryParams()); // <-- Changed
+ }
+
+ public function testWithQueryParamsEmptyArray()
+ {
+ $request = $this->requestFactory();
+ $clone = $request->withQueryParams([]);
+ $cloneUri = $clone->getUri();
+
+ $this->assertEquals('abc=123', $cloneUri->getQuery()); // <-- Unchanged
+ $this->assertEquals([], $clone->getQueryParams()); // <-- Changed
+ }
+
+ public function testGetQueryParamsWithoutUri()
+ {
+ $request = $this->requestFactory();
+ $prop = new ReflectionProperty($request, 'uri');
+ $prop->setAccessible(true);
+ $prop->setValue($request, null);
+
+ $this->assertEquals([], $request->getQueryParams());
+ }
+
+ public function testWithUploadedFiles()
+ {
+ $files = [new UploadedFile('foo.txt'), new UploadedFile('bar.txt')];
+
+ $request = $this->requestFactory();
+ $prevUploaded = $request->getUploadedFiles();
+ $clone = $request->withUploadedFiles($files);
+
+ $this->assertEquals($prevUploaded, $request->getUploadedFiles());
+ $this->assertEquals($files, $clone->getUploadedFiles());
+ }
+
+ public function testGetServerParams()
+ {
+ $mockEnv = Environment::mock(["HTTP_AUTHORIZATION" => "test"]);
+ $request = $this->requestFactory(["HTTP_AUTHORIZATION" => "test"]);
+
+ $serverParams = $request->getServerParams();
+ foreach ($serverParams as $key => $value) {
+ if ($key == 'REQUEST_TIME' || $key == 'REQUEST_TIME_FLOAT') {
+ $this->assertGreaterThanOrEqual(
+ $mockEnv[$key],
+ $value,
+ sprintf("%s value of %s was less than expected value of %s", $key, $value, $mockEnv[$key])
+ );
+ } else {
+ $this->assertEquals(
+ $mockEnv[$key],
+ $value,
+ sprintf("%s value of %s did not equal expected value of %s", $key, $value, $mockEnv[$key])
+ );
+ }
+ }
+ }
+
+ public function testGetAttributes()
+ {
+ $request = $this->requestFactory();
+ $attrProp = new ReflectionProperty($request, 'attributes');
+ $attrProp->setAccessible(true);
+ $attrProp->setValue($request, ['foo' => 'bar']);
+
+ $this->assertEquals(['foo' => 'bar'], $request->getAttributes());
+ }
+
+ public function testGetAttribute()
+ {
+ $request = $this->requestFactory();
+ $attrProp = new ReflectionProperty($request, 'attributes');
+ $attrProp->setAccessible(true);
+ $attrProp->setValue($request, ['foo' => 'bar']);
+
+ $this->assertEquals('bar', $request->getAttribute('foo'));
+ $this->assertNull($request->getAttribute('bar'));
+ $this->assertEquals(2, $request->getAttribute('bar', 2));
+ }
+
+ public function testWithAttribute()
+ {
+ $request = $this->requestFactory();
+ $attrProp = new ReflectionProperty($request, 'attributes');
+ $attrProp->setAccessible(true);
+ $attrProp->setValue($request, ['foo' => 'bar']);
+ $clone = $request->withAttribute('test', '123');
+
+ $this->assertEquals('123', $clone->getAttribute('test'));
+ }
+
+ public function testWithoutAttribute()
+ {
+ $request = $this->requestFactory();
+ $attrProp = new ReflectionProperty($request, 'attributes');
+ $attrProp->setAccessible(true);
+ $attrProp->setValue($request, ['foo' => 'bar']);
+ $clone = $request->withoutAttribute('foo');
+
+ $this->assertNull($clone->getAttribute('foo'));
+ }
+
+ public function testGetParsedBodyWhenAlreadyParsed()
+ {
+ $request = $this->requestFactory();
+ $prop = new ReflectionProperty($request, 'parsedBody');
+ $prop->setAccessible(true);
+ $prop->setValue($request, ['foo' => 'bar']);
+
+ $this->assertEquals(['foo' => 'bar'], $request->getParsedBody());
+ }
+
+ public function testGetParsedBodyWhenBodyDoesNotExist()
+ {
+ $request = $this->requestFactory();
+ $prop = new ReflectionProperty($request, 'body');
+ $prop->setAccessible(true);
+ $prop->setValue($request, null);
+
+ $this->assertNull($request->getParsedBody());
+ }
+
+ public function testWithParsedBody()
+ {
+ $clone = $this->requestFactory()->withParsedBody(['xyz' => '123']);
+
+ $this->assertEquals(['xyz' => '123'], $clone->getParsedBody());
+ }
+
+ public function testWithParsedBodyEmptyArray()
+ {
+ $method = 'GET';
+ $uri = new Uri('https', 'example.com', 443, '/foo/bar', 'abc=123', '', '');
+ $headers = new Headers();
+ $headers->setHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf8');
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+ $body->write('foo=bar');
+ $request = new Request($method, $uri, $headers, $cookies, $serverParams, $body);
+
+ $clone = $request->withParsedBody([]);
+
+ $this->assertEquals([], $clone->getParsedBody());
+ }
+
+ public function testWithParsedBodyNull()
+ {
+ $method = 'GET';
+ $uri = new Uri('https', 'example.com', 443, '/foo/bar', 'abc=123', '', '');
+ $headers = new Headers();
+ $headers->setHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf8');
+ $cookies = [];
+ $serverParams = [];
+ $body = (new StreamFactory())->createStream();
+ $body->write('foo=bar');
+ $request = new Request($method, $uri, $headers, $cookies, $serverParams, $body);
+
+ $clone = $request->withParsedBody(null);
+
+ $this->assertNull($clone->getParsedBody());
+ }
+
+ public function testGetParsedBodyReturnsNullWhenThereIsNoBodyData()
+ {
+ $request = $this->requestFactory(['REQUEST_METHOD' => 'POST']);
+
+ $this->assertNull($request->getParsedBody());
+ }
+
+ public function testGetParsedBodyReturnsNullWhenThereIsNoMediaTypeParserRegistered()
+ {
+ $request = $this->requestFactory([
+ 'REQUEST_METHOD' => 'POST',
+ 'CONTENT_TYPE' => 'text/csv',
+ ]);
+ $request->getBody()->write('foo,bar,baz');
+
+ $this->assertNull($request->getParsedBody());
+ }
+
+ public function testWithParsedBodyInvalid()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->requestFactory()->withParsedBody(2);
+ }
+
+ public function testWithParsedBodyInvalidFalseValue()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->requestFactory()->withParsedBody(false);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/ResponseTest.php b/api_candidatos/vendor/slim/psr7/tests/ResponseTest.php
new file mode 100644
index 0000000..7b73488
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/ResponseTest.php
@@ -0,0 +1,191 @@
+setAccessible(true);
+
+ $bodyReflection = new ReflectionProperty($response, 'body');
+ $bodyReflection->setAccessible(true);
+
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertInstanceOf(Headers::class, $headersReflection->getValue($response));
+ $this->assertInstanceOf(Stream::class, $bodyReflection->getValue($response));
+ }
+
+ public function testConstructorWithCustomArgs()
+ {
+ $headers = new Headers();
+ $body = new Stream(fopen('php://temp', 'r+'));
+ $response = new Response(404, $headers, $body);
+
+ $headersReflection = new ReflectionProperty($response, 'headers');
+ $headersReflection->setAccessible(true);
+
+ $bodyReflection = new ReflectionProperty($response, 'body');
+ $bodyReflection->setAccessible(true);
+
+ $this->assertEquals(404, $response->getStatusCode());
+ $this->assertSame($headers, $headersReflection->getValue($response));
+ $this->assertSame($body, $bodyReflection->getValue($response));
+ }
+
+ public function testDeepCopyClone()
+ {
+ $headers = new Headers();
+ $body = new Stream(fopen('php://temp', 'r+'));
+ $response = new Response(404, $headers, $body);
+ $clone = clone $response;
+
+ $headersReflection = new ReflectionProperty($response, 'headers');
+ $headersReflection->setAccessible(true);
+
+ $this->assertEquals(404, $clone->getStatusCode());
+ $this->assertEquals('1.1', $clone->getProtocolVersion());
+ $this->assertNotSame($headers, $headersReflection->getValue($clone));
+ }
+
+ public function testDisableSetter()
+ {
+ $response = new Response();
+ $response->foo = 'bar';
+
+ $this->assertFalse(property_exists($response, 'foo'));
+ }
+
+ public function testGetStatusCode()
+ {
+ $response = new Response();
+ $responseStatus = new ReflectionProperty($response, 'status');
+ $responseStatus->setAccessible(true);
+ $responseStatus->setValue($response, 404);
+
+ $this->assertEquals(404, $response->getStatusCode());
+ }
+
+ public function testWithStatus()
+ {
+ $response = new Response();
+ $clone = $response->withStatus(302);
+
+ $this->assertEquals(302, $clone->getStatusCode());
+ }
+
+ public function testWithStatusInvalidStatusCodeThrowsException()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $response = new Response();
+ $response->withStatus(800);
+ }
+
+ public function testWithStatusInvalidReasonPhraseThrowsException()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Response reason phrase must be a string');
+
+ $response = new Response();
+ $response->withStatus(200, null);
+ }
+
+ public function testWithStatusEmptyReasonPhrase()
+ {
+ $responseWithNoMessage = new Response(310);
+
+ $this->assertEquals('', $responseWithNoMessage->getReasonPhrase());
+ }
+
+ public function testReasonPhraseContainsCarriageReturn()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Reason phrase contains one of the following prohibited characters: \r \n');
+
+ $response = new Response();
+ $response = $response->withStatus(404, "Not Found\r");
+ }
+
+ public function testReasonPhraseContainsLineFeed()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Reason phrase contains one of the following prohibited characters: \r \n');
+
+ $response = new Response();
+ $response = $response->withStatus(404, "Not Found\n");
+ }
+
+ public function testWithStatusValidReasonPhraseObject()
+ {
+ $response = new Response();
+ $response = $response->withStatus(200, new StringableTestObject('Slim OK'));
+ $this->assertEquals('Slim OK', $response->getReasonPhrase());
+ }
+
+ public function testGetReasonPhrase()
+ {
+ $response = new Response(404);
+
+ $this->assertEquals('Not Found', $response->getReasonPhrase());
+ }
+
+ public function testEmptyReasonPhraseForUnrecognisedCode()
+ {
+ $response = new Response();
+ $response = $response->withStatus(199);
+
+ $this->assertSame('', $response->getReasonPhrase());
+ }
+
+ public function testSetReasonPhraseForUnrecognisedCode()
+ {
+ $response = new Response();
+ $response = $response->withStatus(199, 'Random Message');
+
+ $this->assertEquals('Random Message', $response->getReasonPhrase());
+ }
+
+ public function testGetCustomReasonPhrase()
+ {
+ $response = new Response();
+ $clone = $response->withStatus(200, 'Custom Phrase');
+
+ $this->assertEquals('Custom Phrase', $clone->getReasonPhrase());
+ }
+
+ public function testResponseHeadersDoNotContainAuthorizationHeader()
+ {
+ $_SERVER = Environment::mock(
+ [
+ 'PHP_AUTH_USER' => 'foo'
+ ]
+ );
+
+ $response = new Response();
+ $this->assertEmpty($response->getHeaders());
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/StreamTest.php b/api_candidatos/vendor/slim/psr7/tests/StreamTest.php
new file mode 100644
index 0000000..0a97197
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/StreamTest.php
@@ -0,0 +1,284 @@
+pipeFh != null) {
+ // prevent broken pipe error message
+ stream_get_contents($this->pipeFh);
+ }
+ }
+
+ public function testIsPipe()
+ {
+ $this->openPipeStream();
+
+ $this->assertTrue($this->pipeStream->isPipe());
+
+ $this->pipeStream->detach();
+ $this->assertFalse($this->pipeStream->isPipe());
+
+ $fhFile = fopen(__FILE__, 'r');
+ $fileStream = new Stream($fhFile);
+ $this->assertFalse($fileStream->isPipe());
+ }
+
+ public function testIsPipeReadable()
+ {
+ $this->openPipeStream();
+
+ $this->assertTrue($this->pipeStream->isReadable());
+ }
+
+ public function testPipeIsNotSeekable()
+ {
+ $this->openPipeStream();
+
+ $this->assertFalse($this->pipeStream->isSeekable());
+ }
+
+ public function testCannotSeekPipe()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->openPipeStream();
+
+ $this->pipeStream->seek(0);
+ }
+
+ public function testCannotTellPipe()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->openPipeStream();
+
+ $this->pipeStream->tell();
+ }
+
+ public function testCannotRewindPipe()
+ {
+ $this->expectException(RuntimeException::class);
+
+ $this->openPipeStream();
+
+ $this->pipeStream->rewind();
+ }
+
+ public function testPipeGetSizeYieldsNull()
+ {
+ $this->openPipeStream();
+
+ $this->assertNull($this->pipeStream->getSize());
+ }
+
+ public function testClosePipe()
+ {
+ $this->openPipeStream();
+
+ // prevent broken pipe error message
+ stream_get_contents($this->pipeFh);
+
+ $this->pipeStream->close();
+ $this->pipeFh = null;
+
+ $this->assertFalse($this->pipeStream->isPipe());
+ }
+
+ public function testPipeToString()
+ {
+ $this->openPipeStream();
+ $content = trim((string) $this->pipeStream);
+
+ $this->assertSame('12', $content);
+ }
+
+ public function testConvertsToStringPartiallyReadNonSeekableStream()
+ {
+ $this->openPipeStream();
+ $head = $this->pipeStream->read(1);
+ $tail = trim((string) $this->pipeStream);
+
+ $this->assertSame('1', $head);
+ $this->assertSame('2', $tail);
+ }
+
+ public function testPipeGetContents()
+ {
+ $this->openPipeStream();
+
+ $contents = trim($this->pipeStream->getContents());
+ $this->assertSame('12', $contents);
+ }
+
+ public function testIsWriteable()
+ {
+ $resource = fopen('php://temp', 'w');
+ $stream = new Stream($resource);
+
+ $this->assertEquals(13, $stream->write('Hello, world!'));
+
+ $this->assertTrue($stream->isWritable());
+ }
+
+ public function testIsReadable()
+ {
+ $resource = fopen('php://temp', 'r');
+ $stream = new Stream($resource);
+
+ $this->assertTrue($stream->isReadable());
+ $this->assertFalse($stream->isWritable());
+ }
+
+ public function testIsWritableAndReadable()
+ {
+ $resource = fopen('php://temp', 'w+');
+ $stream = new Stream($resource);
+
+ $stream->write('Hello, world!');
+
+ $this->assertEquals('Hello, world!', $stream);
+
+ $this->assertTrue($stream->isWritable());
+ $this->assertTrue($stream->isReadable());
+ }
+
+ /**
+ * Test that a call to the protected method `attach` would invoke `detach`.
+ *
+ * @throws ReflectionException
+ */
+ public function testAttachAgain()
+ {
+ $this->openPipeStream();
+
+ $streamProphecy = $this->prophesize(Stream::class);
+
+ /** @noinspection PhpUndefinedMethodInspection */
+ $streamProphecy->detach()->shouldBeCalled();
+
+ /** @var Stream $stream */
+ $stream = $streamProphecy->reveal();
+
+ $streamProperty = new ReflectionProperty(Stream::class, 'stream');
+ $streamProperty->setAccessible(true);
+ $streamProperty->setValue($stream, $this->pipeFh);
+
+ $attachMethod = new ReflectionMethod(Stream::class, 'attach');
+ $attachMethod->setAccessible(true);
+ $attachMethod->invoke($stream, $this->pipeFh);
+ }
+
+ public function testGetMetaDataReturnsNullIfStreamIsDetached()
+ {
+ $resource = fopen('php://temp', 'rw+');
+ $stream = new Stream($resource);
+ $stream->detach();
+
+ $this->assertNull($stream->getMetadata());
+ }
+
+ private function openPipeStream()
+ {
+ $this->pipeFh = popen('echo 12', 'r');
+ $this->pipeStream = new Stream($this->pipeFh);
+ }
+
+ public function testReadOnlyCachedStreamsAreDisallowed()
+ {
+ $resource = fopen('php://temp', 'w+');
+ $cache = new Stream(fopen('php://temp', 'r'));
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Cache stream must be seekable and writable');
+ new Stream($resource, $cache);
+ }
+
+ public function testNonSeekableCachedStreamsAreDisallowed()
+ {
+ $resource = fopen('php://temp', 'w+');
+ $cache = new Stream(fopen('php://output', 'w'));
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Cache stream must be seekable and writable');
+
+ new Stream($resource, $cache);
+ }
+
+ public function testCachedStreamsGetsContentFromTheCache()
+ {
+ $resource = popen('echo HelloWorld', 'r');
+ $stream = new Stream($resource, new Stream(fopen('php://temp', 'w+')));
+
+ $this->assertEquals("HelloWorld\n", $stream->getContents());
+ $this->assertEquals("HelloWorld\n", $stream->getContents());
+ }
+
+ public function testCachedStreamsFillsCacheOnRead()
+ {
+ $resource = fopen('data://,0', 'r');
+ $stream = new Stream($resource, new Stream(fopen('php://temp', 'w+')));
+
+ $this->assertEquals("0", $stream->read(100));
+ $this->assertEquals("0", $stream->__toString());
+ }
+
+ public function testDetachingStreamDropsCache()
+ {
+ $cache = new Stream(fopen('php://temp', 'w+'));
+ $resource = fopen('data://,foo', 'r');
+ $stream = new Stream($resource, $cache);
+
+ $stream->detach();
+
+ $cacheProperty = new ReflectionProperty(Stream::class, 'cache');
+ $cacheProperty->setAccessible(true);
+ $finishedProperty = new ReflectionProperty(Stream::class, 'finished');
+ $finishedProperty->setAccessible(true);
+
+ $this->assertNull($cacheProperty->getValue($stream));
+ $this->assertFalse($finishedProperty->getValue($stream));
+ }
+
+ public function testCachedStreamsRewindIfFinishedOnToString()
+ {
+ $resource = fopen('data://,foo', 'r');
+
+ $stream = new Stream($resource, new Stream(fopen('php://temp', 'w+')));
+
+ $this->assertEquals('foo', (string)$stream);
+ $this->assertEquals('foo', (string)$stream);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/StringableTestObject.php b/api_candidatos/vendor/slim/psr7/tests/StringableTestObject.php
new file mode 100644
index 0000000..36a6785
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/StringableTestObject.php
@@ -0,0 +1,23 @@
+value;
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/UploadedFileTest.php b/api_candidatos/vendor/slim/psr7/tests/UploadedFileTest.php
new file mode 100644
index 0000000..fa13a0c
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/UploadedFileTest.php
@@ -0,0 +1,676 @@
+assertEquals($expected, $uploadedFile);
+ }
+
+ /**
+ * @param array $input The input array to parse.
+ *
+ * @dataProvider providerCreateFromGlobals
+ */
+ public function testCreateFromGlobalsFromUserData(array $input)
+ {
+ //If slim.files provided - it will return what was provided
+ $userData['slim.files'] = $input;
+
+ $uploadedFile = UploadedFile::createFromGlobals(Environment::mock($userData));
+ $this->assertEquals($input, $uploadedFile);
+ }
+
+ public function testCreateFromGlobalsWithoutFile()
+ {
+ unset($_FILES);
+
+ $uploadedFile = UploadedFile::createFromGlobals(Environment::mock());
+ $this->assertEquals([], $uploadedFile);
+ }
+
+ public function testConstructor(): UploadedFile
+ {
+ $attr = [
+ 'tmp_name' => self::$filename,
+ 'name' => 'my-avatar.txt',
+ 'size' => 8,
+ 'type' => 'text/plain',
+ 'error' => 0,
+ ];
+
+ $uploadedFile = new UploadedFile(
+ $attr['tmp_name'],
+ $attr['name'],
+ $attr['type'],
+ $attr['size'],
+ $attr['error'],
+ false
+ );
+
+ $this->assertEquals($attr['name'], $uploadedFile->getClientFilename());
+ $this->assertEquals($attr['type'], $uploadedFile->getClientMediaType());
+ $this->assertEquals($attr['size'], $uploadedFile->getSize());
+ $this->assertEquals($attr['error'], $uploadedFile->getError());
+ $this->assertEquals($attr['tmp_name'], $uploadedFile->getFilePath());
+
+ return $uploadedFile;
+ }
+
+ public function testConstructorSapi(): UploadedFile
+ {
+ $attr = [
+ 'tmp_name' => self::$filename,
+ 'name' => 'my-avatar.txt',
+ 'size' => 8,
+ 'type' => 'text/plain',
+ 'error' => 0,
+ ];
+
+ $uploadedFile = new UploadedFile(
+ $attr['tmp_name'],
+ $attr['name'],
+ $attr['type'],
+ $attr['size'],
+ $attr['error'],
+ true
+ );
+
+ $this->assertEquals($attr['name'], $uploadedFile->getClientFilename());
+ $this->assertEquals($attr['type'], $uploadedFile->getClientMediaType());
+ $this->assertEquals($attr['size'], $uploadedFile->getSize());
+ $this->assertEquals($attr['error'], $uploadedFile->getError());
+ $this->assertEquals($attr['tmp_name'], $uploadedFile->getFilePath());
+
+ return $uploadedFile;
+ }
+
+ /**
+ * @depends testConstructor
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ * @return UploadedFile
+ */
+ public function testGetStream(UploadedFile $uploadedFile): UploadedFile
+ {
+ $stream = $uploadedFile->getStream();
+ $this->assertEquals(true, $uploadedFile->getStream() instanceof Stream);
+ $stream->close();
+
+ return $uploadedFile;
+ }
+
+ /**
+ * @depends testConstructor
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ */
+ public function testMoveToNotWritable(UploadedFile $uploadedFile)
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $tempName = uniqid('file-');
+ $path = 'some_random_dir' . DIRECTORY_SEPARATOR . $tempName;
+ $uploadedFile->moveTo($path);
+ }
+
+ /**
+ * @depends testConstructor
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ * @return UploadedFile
+ */
+ public function testMoveTo(UploadedFile $uploadedFile): UploadedFile
+ {
+ $tempName = uniqid('file-');
+ $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName;
+ $uploadedFile->moveTo($path);
+
+ $this->assertFileExists($path);
+
+ unlink($path);
+
+ return $uploadedFile;
+ }
+
+ public function testMoveToRenameFailure()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessageMatches('/^Error moving uploaded file .* to .*$/');
+
+ $uploadedFile = $this->generateNewTmpFile();
+
+ $tempName = uniqid('file-');
+ $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName;
+
+ $GLOBALS['rename_return'] = false;
+ $uploadedFile->moveTo($path);
+ }
+
+ /**
+ * @depends testConstructorSapi
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ */
+ public function testMoveToSapiNonUploadedFile(UploadedFile $uploadedFile)
+ {
+ $this->expectException(RuntimeException::class);
+
+ $tempName = uniqid('file-');
+ $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName;
+ $uploadedFile->moveTo($path);
+ }
+
+ /**
+ * @depends testConstructorSapi
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ */
+ public function testMoveToSapiMoveUploadedFileFails(UploadedFile $uploadedFile)
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessageMatches('~Error moving uploaded file.*~');
+
+ $GLOBALS['is_uploaded_file_return'] = true;
+
+ $tempName = uniqid('file-');
+ $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName;
+ $uploadedFile->moveTo($path);
+ }
+
+ /**
+ * @depends testMoveTo
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ */
+ public function testMoveToCannotBeDoneTwice(UploadedFile $uploadedFile)
+ {
+ $this->expectException(RuntimeException::class);
+
+ $tempName = uniqid('file-');
+ $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName;
+ $uploadedFile->moveTo($path);
+ $this->assertFileExists($path);
+ unlink($path);
+
+ $uploadedFile->moveTo($path);
+ }
+
+ /**
+ * This test must run after testMoveTo
+ *
+ * @depends testConstructor
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ */
+ public function testMoveToAgain(UploadedFile $uploadedFile)
+ {
+ $this->expectException(RuntimeException::class);
+
+ $tempName = uniqid('file-');
+ $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName;
+ $uploadedFile->moveTo($path);
+ }
+
+ /**
+ * This test must run after testMoveTo
+ *
+ * @depends testConstructor
+ *
+ * @param UploadedFile $uploadedFile
+ *
+ */
+ public function testMovedStream(UploadedFile $uploadedFile)
+ {
+ $this->expectException(RuntimeException::class);
+
+ $uploadedFile->getStream();
+ }
+
+ public function testMoveToStream()
+ {
+ $uploadedFile = $this->generateNewTmpFile();
+
+ $fileProperty = new ReflectionProperty($uploadedFile, 'file');
+ $fileProperty->setAccessible(true);
+ $fileName = $fileProperty->getValue($uploadedFile);
+
+ $contents = file_get_contents($fileName);
+
+ ob_start();
+ $uploadedFile->moveTo('php://output');
+ $movedFileContents = ob_get_clean();
+
+ $this->assertEquals($contents, $movedFileContents);
+ $this->assertFileDoesNotExist($fileName);
+ }
+
+ public function testMoveToStreamCopyFailure()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Error moving uploaded file to php://output');
+
+ $uploadedFile = $this->generateNewTmpFile();
+
+ $GLOBALS['copy_return'] = false;
+ $uploadedFile->moveTo('php://output');
+ }
+
+ public function testFileUploadWithTempStream()
+ {
+ $streamFactory = function (...$args) {
+ return (new StreamFactory())->createStream(...$args);
+ };
+ $uploadedFileFactory = function (...$args) {
+ return (new UploadedFileFactory())->createUploadedFile(...$args);
+ };
+ $this->runFileUploadWithTempStreamTest($streamFactory, $uploadedFileFactory);
+ }
+
+ /**
+ * This test sequence has been inspired by UploadedFileFactoryTestCase from http-interop/http-factory-tests package.
+ *
+ * @param callable $streamFactory
+ * @param callable $uploadedFileFactory
+ */
+ private function runFileUploadWithTempStreamTest(callable $streamFactory, callable $uploadedFileFactory)
+ {
+ $content = 'this is your capitan speaking';
+ $error = UPLOAD_ERR_OK;
+ $clientFilename = 'test.txt';
+ $clientMediaType = 'text/plain';
+
+ $stream = call_user_func($streamFactory, $content);
+ $file = call_user_func(
+ $uploadedFileFactory,
+ $stream,
+ strlen($content),
+ $error,
+ $clientFilename,
+ $clientMediaType
+ );
+
+ $this->assertInstanceOf(UploadedFileInterface::class, $file);
+ $this->assertSame($content, (string)$file->getStream());
+ $this->assertSame(strlen($content), $file->getSize());
+ $this->assertSame($error, $file->getError());
+ $this->assertSame($clientFilename, $file->getClientFilename());
+ $this->assertSame($clientMediaType, $file->getClientMediaType());
+ $this->assertSame($stream->getMetadata('uri'), $file->getFilePath());
+ }
+
+ public function testCreateUploadedFileWithInvalidArguments()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ new UploadedFile(42); // a random value that is neither a string nor an instance of StreamInterface
+ }
+
+ public function testCreateUploadedFileWithInvalidUri()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $streamProphecy = $this->prophesize(StreamInterface::class);
+
+ /** @noinspection PhpUndefinedMethodInspection */
+ $streamProphecy
+ ->getMetadata('uri')
+ ->willReturn(null)
+ ->shouldBeCalled();
+ $stream = $streamProphecy->reveal();
+
+ // Test with a StreamInterface that returns `null`
+ // when `$stream->getMetadata('uri')` is called (which is an invalid case).
+ new UploadedFile($stream);
+ }
+
+ public static function providerCreateFromGlobals(): array
+ {
+ return [
+ // no nest:
+ [
+ // $_FILES array
+ [
+ 'avatar' => [
+ 'tmp_name' => 'phpUxcOty',
+ 'name' => 'my-avatar.png',
+ 'size' => 90996,
+ 'type' => 'image/png',
+ 'error' => 0,
+ ],
+ ],
+ // expected format of array
+ [
+ 'avatar' => new UploadedFile('phpUxcOty', 'my-avatar.png', 'image/png', 90996, UPLOAD_ERR_OK, true)
+ ]
+ ],
+ // no nest, with error:
+ [
+ // $_FILES array
+ [
+ 'avatar' => [
+ 'tmp_name' => 'phpUxcOty',
+ 'name' => 'my-avatar.png',
+ 'size' => 90996,
+ 'type' => 'image/png',
+ 'error' => 7,
+ ],
+ ],
+ // expected format of array
+ [
+ 'avatar' => new UploadedFile(
+ 'phpUxcOty',
+ 'my-avatar.png',
+ 'image/png',
+ 90996,
+ UPLOAD_ERR_CANT_WRITE,
+ true
+ )
+ ]
+ ],
+
+ // array of files:
+ [
+ // $_FILES array
+ [
+ 'avatars' => [
+ 'tmp_name' => [
+ 0 => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ 1 => __DIR__ . DIRECTORY_SEPARATOR . 'file1.html',
+ ],
+ 'name' => [
+ 0 => 'file0.txt',
+ 1 => 'file1.html',
+ ],
+ 'type' => [
+ 0 => 'text/plain',
+ 1 => 'text/html',
+ ],
+ 'error' => [
+ 0 => 0,
+ 1 => 0
+ ],
+ 'size' => [
+ 0 => 0,
+ 1 => 0
+ ]
+ ],
+ ],
+ // expected format of array
+ [
+ 'avatars' => [
+ 0 => new UploadedFile(
+ __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ 'file0.txt',
+ 'text/plain',
+ null,
+ UPLOAD_ERR_OK,
+ true
+ ),
+ 1 => new UploadedFile(
+ __DIR__ . DIRECTORY_SEPARATOR . 'file1.html',
+ 'file1.html',
+ 'text/html',
+ null,
+ UPLOAD_ERR_OK,
+ true
+ ),
+ ],
+ ]
+ ],
+ // array of files as multidimensional array:
+ [
+ // $_FILES array
+ [
+ [
+ 'avatars' => [
+ 'tmp_name' => [
+ 0 => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ 1 => __DIR__ . DIRECTORY_SEPARATOR . 'file1.html',
+ ],
+ 'name' => [
+ 0 => 'file0.txt',
+ 1 => 'file1.html',
+ ],
+ 'type' => [
+ 0 => 'text/plain',
+ 1 => 'text/html',
+ ],
+ 'size' => [
+ 0 => 0,
+ 1 => 0,
+ ],
+ ],
+ ],
+ ],
+ // expected format of array
+ [
+ 0 =>
+ [
+ 'avatars' =>
+ [
+ 'tmp_name' => [],
+ 'name' => [],
+ 'type' => [],
+ 'size' => [],
+ ],
+ ],
+ ],
+ ],
+ // single nested file:
+ [
+ // $_FILES array
+ [
+ 'details' => [
+ 'tmp_name' => [
+ 'avatar' => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ ],
+ 'name' => [
+ 'avatar' => 'file0.txt',
+ ],
+ 'type' => [
+ 'avatar' => 'text/plain',
+ ],
+ 'error' => [
+ 'avatar' => 0,
+ ],
+ 'size' => [
+ 'avatar' => 0,
+ ],
+ ],
+ ],
+ // expected format of array
+ [
+ 'details' => [
+ 'avatar' => new UploadedFile(
+ __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ 'file0.txt',
+ 'text/plain',
+ null,
+ UPLOAD_ERR_OK,
+ true
+ ),
+ ],
+ ]
+ ],
+ // nested array of files:
+ [
+ [
+ 'files' => [
+ 'tmp_name' => [
+ 'details' => [
+ 'avatar' => [
+ 0 => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ 1 => __DIR__ . DIRECTORY_SEPARATOR . 'file1.html',
+ ],
+ ],
+ ],
+ 'name' => [
+ 'details' => [
+ 'avatar' => [
+ 0 => 'file0.txt',
+ 1 => 'file1.html',
+ ],
+ ],
+ ],
+ 'type' => [
+ 'details' => [
+ 'avatar' => [
+ 0 => 'text/plain',
+ 1 => 'text/html',
+ ],
+ ],
+ ],
+ 'error' => [
+ 'details' => [
+ 'avatar' => [
+ 0 => 0,
+ 1 => 0
+ ],
+ ],
+ ],
+ 'size' => [
+ 'details' => [
+ 'avatar' => [
+ 0 => 0,
+ 1 => 0
+ ],
+ ],
+ ],
+ ],
+ ],
+ // expected format of array
+ [
+ 'files' => [
+ 'details' => [
+ 'avatar' => [
+ 0 => new UploadedFile(
+ __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt',
+ 'file0.txt',
+ 'text/plain',
+ null,
+ UPLOAD_ERR_OK,
+ true
+ ),
+ 1 => new UploadedFile(
+ __DIR__ . DIRECTORY_SEPARATOR . 'file1.html',
+ 'file1.html',
+ 'text/html',
+ null,
+ UPLOAD_ERR_OK,
+ true
+ ),
+ ],
+ ],
+ ],
+ ]
+ ],
+ ];
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/UriTest.php b/api_candidatos/vendor/slim/psr7/tests/UriTest.php
new file mode 100644
index 0000000..aeb3a85
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/UriTest.php
@@ -0,0 +1,383 @@
+ 80,
+ 'wss' => 443,
+ ];
+ };
+
+ $this->assertEquals('ws', $wsUri->getScheme());
+ }
+
+ public function testGetScheme()
+ {
+ $this->assertEquals('https', $this->uriFactory()->getScheme());
+ }
+
+ public function testWithScheme()
+ {
+ $uri = $this->uriFactory()->withScheme('http');
+
+ $this->assertEquals('http', $uri->getScheme());
+ }
+
+ public function testWithSchemeRemovesSuffix()
+ {
+ $uri = $this->uriFactory()->withScheme('http://');
+
+ $this->assertEquals('http', $uri->getScheme());
+ }
+
+ public function testWithSchemeEmpty()
+ {
+ $uri = $this->uriFactory()->withScheme('');
+
+ $this->assertEquals('', $uri->getScheme());
+ }
+
+ public function testWithSchemeInvalid()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessageMatches('/^Uri scheme must be one of:.*$/');
+
+ $this->uriFactory()->withScheme('ftp');
+ }
+
+ public function testWithSchemeInvalidType()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Uri scheme must be a string');
+
+ $this->uriFactory()->withScheme([]);
+ }
+
+ public function testGetAuthorityWithUsernameAndPassword()
+ {
+ $this->assertEquals('josh:sekrit@example.com', $this->uriFactory()->getAuthority());
+ }
+
+ public function testWithUserInfo()
+ {
+ $uri = $this->uriFactory()->withUserInfo('bob', 'pass');
+
+ $this->assertEquals('bob:pass', $uri->getUserInfo());
+ }
+
+ public function testWithUserInfoEncodesCorrectly()
+ {
+ $uri = $this->uriFactory()->withUserInfo('bob@example.com', 'pass:word');
+
+ $this->assertEquals('bob%40example.com:pass%3Aword', $uri->getUserInfo());
+ }
+
+ public function testWithUserInfoRemovesPassword()
+ {
+ $uri = $this->uriFactory()->withUserInfo('bob');
+
+ $this->assertEquals('bob', $uri->getUserInfo());
+ }
+
+ public function testWithUserInfoRemovesInfo()
+ {
+ $uri = $this->uriFactory()->withUserInfo('bob', 'password');
+ $uri = $uri->withUserInfo('');
+
+ $this->assertEquals('', $uri->getUserInfo());
+ }
+
+ public function testGetHost()
+ {
+ $this->assertEquals('example.com', $this->uriFactory()->getHost());
+ }
+
+ public function testWithHost()
+ {
+ $uri = $this->uriFactory()->withHost('slimframework.com');
+
+ $this->assertEquals('slimframework.com', $uri->getHost());
+ }
+
+ public function testWithHostValidObject()
+ {
+ $mock = new StringableTestObject('host.test');
+
+ $uri = $this->uriFactory()->withHost($mock);
+ $this->assertEquals('host.test', $uri->getHost());
+ }
+
+ public function testWithHostInvalidObject()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Uri host must be a string');
+
+ $this->uriFactory()->withHost(new stdClass());
+ }
+
+ public function testFilterHost()
+ {
+ $uri = new Uri('http', '2001:db8::1');
+
+ $this->assertEquals('[2001:db8::1]', $uri->getHost());
+ }
+
+ public function testGetPortWithSchemeAndNonDefaultPort()
+ {
+ $uri = new Uri('https', 'www.example.com', 4000);
+
+ $this->assertEquals(4000, $uri->getPort());
+ }
+
+ public function testGetPortWithSchemeAndDefaultPort()
+ {
+ $uriHttp = new Uri('http', 'www.example.com', 80);
+ $uriHttps = new Uri('https', 'www.example.com', 443);
+
+ $this->assertNull($uriHttp->getPort());
+ $this->assertNull($uriHttps->getPort());
+ }
+
+ public function testGetPortWithoutSchemeAndPort()
+ {
+ $uri = new Uri('', 'www.example.com');
+
+ $this->assertNull($uri->getPort());
+ }
+
+ public function testGetPortWithSchemeWithoutPort()
+ {
+ $uri = new Uri('http', 'www.example.com');
+
+ $this->assertNull($uri->getPort());
+ }
+
+ public function testWithPort()
+ {
+ $uri = $this->uriFactory()->withPort(8000);
+
+ $this->assertEquals(8000, $uri->getPort());
+ }
+
+ public function testWithPortNull()
+ {
+ $uri = $this->uriFactory()->withPort(null);
+
+ $this->assertEquals(null, $uri->getPort());
+ }
+
+ public function testWithPortInvalidInt()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->uriFactory()->withPort(70000);
+ }
+
+ public function testWithPortInvalidString()
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $this->uriFactory()->withPort('Foo');
+ }
+
+ public function testWithPortIntegerAsString()
+ {
+ $uri = $this->uriFactory()->withPort("199");
+
+ $this->assertEquals(199, $uri->getPort());
+ }
+
+ public function testGetPath()
+ {
+ $this->assertEquals('/foo/bar', $this->uriFactory()->getPath());
+ }
+
+ public function testWithPath()
+ {
+ $uri = $this->uriFactory()->withPath('/new');
+
+ $this->assertEquals('/new', $uri->getPath());
+ }
+
+ public function testWithPathWithoutPrefix()
+ {
+ $uri = $this->uriFactory()->withPath('new');
+
+ $this->assertEquals('new', $uri->getPath());
+ }
+
+ public function testWithPathEmptyValue()
+ {
+ $uri = $this->uriFactory()->withPath('');
+
+ $this->assertEquals('', $uri->getPath());
+ }
+
+ public function testWithPathUrlEncodesInput()
+ {
+ $uri = $this->uriFactory()->withPath('/includes?/new');
+
+ $this->assertEquals('/includes%3F/new', $uri->getPath());
+ }
+
+ public function testWithPathDoesNotDoubleEncodeInput()
+ {
+ $uri = $this->uriFactory()->withPath('/include%25s/new');
+
+ $this->assertEquals('/include%25s/new', $uri->getPath());
+ }
+
+ public function testWithPathInvalidType()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Uri path must be a string');
+
+ $this->uriFactory()->withPath(['foo']);
+ }
+
+ public function testGetQuery()
+ {
+ $this->assertEquals('abc=123', $this->uriFactory()->getQuery());
+ }
+
+ public function testWithQuery()
+ {
+ $uri = $this->uriFactory()->withQuery('xyz=123');
+
+ $this->assertEquals('xyz=123', $uri->getQuery());
+ }
+
+ public function testWithQueryRemovesPrefix()
+ {
+ $uri = $this->uriFactory()->withQuery('?xyz=123');
+
+ $this->assertEquals('xyz=123', $uri->getQuery());
+ }
+
+ public function testWithQueryEmpty()
+ {
+ $uri = $this->uriFactory()->withQuery('');
+
+ $this->assertEquals('', $uri->getQuery());
+ }
+
+ public function testWithQueryValidObject()
+ {
+ $mock = new StringableTestObject('xyz=123');
+
+ $uri = $this->uriFactory()->withQuery($mock);
+ $this->assertEquals('xyz=123', $uri->getQuery());
+ }
+
+ public function testFilterQuery()
+ {
+ $uri = $this->uriFactory()->withQuery('?foobar=%match');
+
+ $this->assertEquals('foobar=%25match', $uri->getQuery());
+ }
+
+ public function testWithQueryInvalidType()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Uri query must be a string');
+
+ $this->uriFactory()->withQuery(['foo']);
+ }
+
+ public function testGetFragment()
+ {
+ $this->assertEquals('section3', $this->uriFactory()->getFragment());
+ }
+
+ public function testWithFragment()
+ {
+ $uri = $this->uriFactory()->withFragment('other-fragment');
+
+ $this->assertEquals('other-fragment', $uri->getFragment());
+ }
+
+ public function testWithFragmentRemovesPrefix()
+ {
+ $uri = $this->uriFactory()->withFragment('#other-fragment');
+
+ $this->assertEquals('other-fragment', $uri->getFragment());
+ }
+
+ public function testWithFragmentEmpty()
+ {
+ $uri = $this->uriFactory()->withFragment('');
+
+ $this->assertEquals('', $uri->getFragment());
+ }
+
+ public function testWithFragmentValidObject()
+ {
+ $mock = new StringableTestObject('other-fragment');
+
+ $uri = $this->uriFactory()->withFragment($mock);
+ $this->assertEquals('other-fragment', $uri->getFragment());
+ }
+
+ public function testWithFragmentUrlEncode()
+ {
+ $uri = $this->uriFactory()->withFragment('^a');
+
+ $this->assertEquals('%5Ea', $uri->getFragment());
+ }
+
+ public function testWithFragmentInvalidType()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Uri fragment must be a string');
+
+ $this->uriFactory()->withFragment(['foo']);
+ }
+
+ public function testToString()
+ {
+ $uri = $this->uriFactory();
+
+ $this->assertEquals('https://josh:sekrit@example.com/foo/bar?abc=123#section3', (string) $uri);
+
+ $uri = $uri->withPath('bar');
+ $this->assertEquals('https://josh:sekrit@example.com/bar?abc=123#section3', (string) $uri);
+
+ $uri = $uri->withPath('/bar');
+ $this->assertEquals('https://josh:sekrit@example.com/bar?abc=123#section3', (string) $uri);
+
+ $uri = $uri->withScheme('')->withHost('')->withPort(null)->withUserInfo('')->withPath('//bar');
+ $this->assertEquals('/bar?abc=123#section3', (string) $uri);
+ }
+}
diff --git a/api_candidatos/vendor/slim/psr7/tests/bootstrap.php b/api_candidatos/vendor/slim/psr7/tests/bootstrap.php
new file mode 100644
index 0000000..eee5637
--- /dev/null
+++ b/api_candidatos/vendor/slim/psr7/tests/bootstrap.php
@@ -0,0 +1,99 @@
+ [
+ 'getallheaders' => function () {
+ if (array_key_exists('getallheaders_return', $GLOBALS)) {
+ return $GLOBALS['getallheaders_return'];
+ }
+
+ return getallheaders();
+ }
+ ],
+ Message::class => [
+ 'header' => function (string $string, bool $replace = true, ?int $statusCode = null): void {
+ HeaderStack::push(
+ [
+ 'header' => $string,
+ 'replace' => $replace,
+ 'status_code' => $statusCode,
+ ]
+ );
+ },
+ 'header_remove' => function ($name = null): void {
+ HeaderStack::remove($name);
+ }
+ ],
+ NonBufferedBody::class => [
+ 'ob_get_level' => function (): int {
+ if (isset($GLOBALS['ob_get_level_shift'])) {
+ return ob_get_level() + $GLOBALS['ob_get_level_shift'];
+ }
+
+ return ob_get_level();
+ }
+ ],
+ UploadedFile::class => [
+ 'copy' => function (string $source, string $destination, $context = null): bool {
+ if (isset($GLOBALS['copy_return'])) {
+ return $GLOBALS['copy_return'];
+ }
+
+ if ($context === null) {
+ return copy($source, $destination);
+ }
+ return copy($source, $destination, $context);
+ },
+ 'is_uploaded_file' => function (string $filename): bool {
+ if (isset($GLOBALS['is_uploaded_file_return'])) {
+ return $GLOBALS['is_uploaded_file_return'];
+ }
+
+ return is_uploaded_file($filename);
+ },
+ 'rename' => function (string $oldName, string $newName, $context = null): bool {
+ if (isset($GLOBALS['rename_return'])) {
+ return $GLOBALS['rename_return'];
+ }
+
+ if ($context === null) {
+ return rename($oldName, $newName);
+ }
+ return rename($oldName, $newName, $context = null);
+ }
+ ],
+ Factory\StreamFactory::class => [
+ 'fopen' => function (string $filename, string $mode) {
+ if (isset($GLOBALS['fopen_return'])) {
+ return isset($GLOBALS['fopen_return']);
+ }
+
+ return fopen($filename, $mode);
+ },
+ 'is_readable' => function (string $filename) {
+ if ($filename === 'non-readable') {
+ return false;
+ }
+
+ return is_readable($filename);
+ }
+ ]
+]);
diff --git a/api_candidatos/vendor/stella-maris/clock/.editorconfig b/api_candidatos/vendor/stella-maris/clock/.editorconfig
new file mode 100644
index 0000000..9cf4437
--- /dev/null
+++ b/api_candidatos/vendor/stella-maris/clock/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+trim_trailing_whitespace = true
+indent_size = tab
+indent_style = tab
+tab_width = 4
+end_of_line = lf
+insert_final_newline = true
+max_line_length = off
+charset = utf-8
+
+[*.{yml,yaml}]
+tab_width = 2
+
diff --git a/api_candidatos/vendor/stella-maris/clock/LICENSE.md b/api_candidatos/vendor/stella-maris/clock/LICENSE.md
new file mode 100644
index 0000000..51aa800
--- /dev/null
+++ b/api_candidatos/vendor/stella-maris/clock/LICENSE.md
@@ -0,0 +1,9 @@
+
+
+Copyright Andreas Heigl and ClockInterfaceContributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/api_candidatos/vendor/stella-maris/clock/README.md b/api_candidatos/vendor/stella-maris/clock/README.md
new file mode 100644
index 0000000..063e556
--- /dev/null
+++ b/api_candidatos/vendor/stella-maris/clock/README.md
@@ -0,0 +1,66 @@
+# Clock
+
+An implementation of the proposed PSR-20 clock-interface
+
+[](https://packagist.org/packages/stella-maris/clock)
+[](https://packagist.org/packages/stella-maris/clock)
+[](https://packagist.org/packages/stella-maris/clock)
+
+[](https://gitlab.com/stella-maris/clock/-/commits/main)
+
+## Installation
+
+```bash
+composer require stella-maris/clock
+```
+
+## Usage
+
+This interface allows one to inject one of the implemntations that provide the
+clock-interface.
+
+```php
+use StellaMaris/Clock/CLockInterface;
+
+final class PastChecker
+{
+ public function __construct(private ClockInterface $clock) {}
+
+ public function hasDateTimeAlreadyPassed(DateTimeImmutable $item): bool
+ {
+ return $item < $this->clock->now();
+ }
+}
+```
+
+## Why
+
+Within the Framework Interoperability Group (FIG) a working group has started in 2021 to
+create a ClockInterface. The works on that have been rather fast and already in the mid of
+2021 the interface was more or less finally decided upon.
+
+### So why this Interface?
+
+Since mid 2021 no further work has been happening on the Working Group. All requests towards
+the editor and the sponsor weren't met with any reaction.
+
+So after a lot of discussions on the official working group channel I decided to bring this
+interface forward by providing the currently agreed upon interface as a separate package
+on packagist.
+
+### But what when the PSR Interface is provided?
+
+There are two possibilities:
+* Either the interface will be provided by the FIG as it is currently,
+then this interface will extend the PSR-20 one so that all implementations of this
+interface will be immediately PSR20 compatible.
+* Or the PSR20 interface will look different: Then all current implementations will
+need to provide a spearate implementation for PSR20 compatibility and this interface will
+simply coexist with the PSR20 one.
+
+## Documentation
+
+For a more thorough information about the interface please check the PSR-20 documentation
+at https://github.com/php-fig/fig-standards/blob/master/proposed/clock.md and
+https://github.com/php-fig/fig-standards/blob/master/proposed/clock-meta.md
+
diff --git a/api_candidatos/vendor/stella-maris/clock/composer.json b/api_candidatos/vendor/stella-maris/clock/composer.json
new file mode 100644
index 0000000..30a5cba
--- /dev/null
+++ b/api_candidatos/vendor/stella-maris/clock/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "stella-maris/clock",
+ "description": "A pre-release of the proposed PSR-20 Clock-Interface",
+ "keywords": [
+ "clock",
+ "psr20",
+ "datetime",
+ "point in time"
+ ],
+ "homepage": "https://gitlab.com/stella-maris/clock",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Andreas Heigl",
+ "role": "Maintainer"
+ }
+ ],
+ "require": {
+ "php": "^7.0|^8.0",
+ "psr/clock": "^1.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "StellaMaris\\Clock\\": "src"
+ }
+ }
+}
diff --git a/api_candidatos/vendor/stella-maris/clock/src/ClockInterface.php b/api_candidatos/vendor/stella-maris/clock/src/ClockInterface.php
new file mode 100644
index 0000000..c310273
--- /dev/null
+++ b/api_candidatos/vendor/stella-maris/clock/src/ClockInterface.php
@@ -0,0 +1,15 @@
+
+ *
+ * Licenses under the MIT-license. For details see the included file LICENSE.md
+ */
+
+namespace StellaMaris\Clock;
+
+use DateTimeImmutable;
+use Psr\Clock\ClockInterface as PsrClockInterface;
+
+interface ClockInterface extends PsrClockInterface
+{
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/LICENSE b/api_candidatos/vendor/symfony/polyfill-php80/LICENSE
new file mode 100644
index 0000000..0ed3a24
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2020-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/Php80.php b/api_candidatos/vendor/symfony/polyfill-php80/Php80.php
new file mode 100644
index 0000000..362dd1a
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/Php80.php
@@ -0,0 +1,115 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php80;
+
+/**
+ * @author Ion Bazan
+ * @author Nico Oelgart
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+final class Php80
+{
+ public static function fdiv(float $dividend, float $divisor): float
+ {
+ return @($dividend / $divisor);
+ }
+
+ public static function get_debug_type($value): string
+ {
+ switch (true) {
+ case null === $value: return 'null';
+ case \is_bool($value): return 'bool';
+ case \is_string($value): return 'string';
+ case \is_array($value): return 'array';
+ case \is_int($value): return 'int';
+ case \is_float($value): return 'float';
+ case \is_object($value): break;
+ case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
+ default:
+ if (null === $type = @get_resource_type($value)) {
+ return 'unknown';
+ }
+
+ if ('Unknown' === $type) {
+ $type = 'closed';
+ }
+
+ return "resource ($type)";
+ }
+
+ $class = \get_class($value);
+
+ if (false === strpos($class, '@')) {
+ return $class;
+ }
+
+ return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
+ }
+
+ public static function get_resource_id($res): int
+ {
+ if (!\is_resource($res) && null === @get_resource_type($res)) {
+ throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
+ }
+
+ return (int) $res;
+ }
+
+ public static function preg_last_error_msg(): string
+ {
+ switch (preg_last_error()) {
+ case \PREG_INTERNAL_ERROR:
+ return 'Internal error';
+ case \PREG_BAD_UTF8_ERROR:
+ return 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ case \PREG_BAD_UTF8_OFFSET_ERROR:
+ return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
+ case \PREG_BACKTRACK_LIMIT_ERROR:
+ return 'Backtrack limit exhausted';
+ case \PREG_RECURSION_LIMIT_ERROR:
+ return 'Recursion limit exhausted';
+ case \PREG_JIT_STACKLIMIT_ERROR:
+ return 'JIT stack limit exhausted';
+ case \PREG_NO_ERROR:
+ return 'No error';
+ default:
+ return 'Unknown error';
+ }
+ }
+
+ public static function str_contains(string $haystack, string $needle): bool
+ {
+ return '' === $needle || false !== strpos($haystack, $needle);
+ }
+
+ public static function str_starts_with(string $haystack, string $needle): bool
+ {
+ return 0 === strncmp($haystack, $needle, \strlen($needle));
+ }
+
+ public static function str_ends_with(string $haystack, string $needle): bool
+ {
+ if ('' === $needle || $needle === $haystack) {
+ return true;
+ }
+
+ if ('' === $haystack) {
+ return false;
+ }
+
+ $needleLength = \strlen($needle);
+
+ return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/PhpToken.php b/api_candidatos/vendor/symfony/polyfill-php80/PhpToken.php
new file mode 100644
index 0000000..cd78c4c
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/PhpToken.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php80;
+
+/**
+ * @author Fedonyuk Anton
+ *
+ * @internal
+ */
+class PhpToken implements \Stringable
+{
+ /**
+ * @var int
+ */
+ public $id;
+
+ /**
+ * @var string
+ */
+ public $text;
+
+ /**
+ * @var -1|positive-int
+ */
+ public $line;
+
+ /**
+ * @var int
+ */
+ public $pos;
+
+ /**
+ * @param -1|positive-int $line
+ */
+ public function __construct(int $id, string $text, int $line = -1, int $position = -1)
+ {
+ $this->id = $id;
+ $this->text = $text;
+ $this->line = $line;
+ $this->pos = $position;
+ }
+
+ public function getTokenName(): ?string
+ {
+ if ('UNKNOWN' === $name = token_name($this->id)) {
+ $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
+ }
+
+ return $name;
+ }
+
+ /**
+ * @param int|string|array $kind
+ */
+ public function is($kind): bool
+ {
+ foreach ((array) $kind as $value) {
+ if (\in_array($value, [$this->id, $this->text], true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function isIgnorable(): bool
+ {
+ return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
+ }
+
+ public function __toString(): string
+ {
+ return (string) $this->text;
+ }
+
+ /**
+ * @return list
+ */
+ public static function tokenize(string $code, int $flags = 0): array
+ {
+ $line = 1;
+ $position = 0;
+ $tokens = token_get_all($code, $flags);
+ foreach ($tokens as $index => $token) {
+ if (\is_string($token)) {
+ $id = \ord($token);
+ $text = $token;
+ } else {
+ [$id, $text, $line] = $token;
+ }
+ $tokens[$index] = new static($id, $text, $line, $position);
+ $position += \strlen($text);
+ }
+
+ return $tokens;
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/README.md b/api_candidatos/vendor/symfony/polyfill-php80/README.md
new file mode 100644
index 0000000..3816c55
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/README.md
@@ -0,0 +1,25 @@
+Symfony Polyfill / Php80
+========================
+
+This component provides features added to PHP 8.0 core:
+
+- [`Stringable`](https://php.net/stringable) interface
+- [`fdiv`](https://php.net/fdiv)
+- [`ValueError`](https://php.net/valueerror) class
+- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
+- `FILTER_VALIDATE_BOOL` constant
+- [`get_debug_type`](https://php.net/get_debug_type)
+- [`PhpToken`](https://php.net/phptoken) class
+- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
+- [`str_contains`](https://php.net/str_contains)
+- [`str_starts_with`](https://php.net/str_starts_with)
+- [`str_ends_with`](https://php.net/str_ends_with)
+- [`get_resource_id`](https://php.net/get_resource_id)
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php
new file mode 100644
index 0000000..2b95542
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#[Attribute(Attribute::TARGET_CLASS)]
+final class Attribute
+{
+ public const TARGET_CLASS = 1;
+ public const TARGET_FUNCTION = 2;
+ public const TARGET_METHOD = 4;
+ public const TARGET_PROPERTY = 8;
+ public const TARGET_CLASS_CONSTANT = 16;
+ public const TARGET_PARAMETER = 32;
+ public const TARGET_ALL = 63;
+ public const IS_REPEATABLE = 64;
+
+ /** @var int */
+ public $flags;
+
+ public function __construct(int $flags = self::TARGET_ALL)
+ {
+ $this->flags = $flags;
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php
new file mode 100644
index 0000000..bd1212f
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
+ class PhpToken extends Symfony\Polyfill\Php80\PhpToken
+ {
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php
new file mode 100644
index 0000000..7c62d75
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+ interface Stringable
+ {
+ /**
+ * @return string
+ */
+ public function __toString();
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php
new file mode 100644
index 0000000..01c6c6c
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+ class UnhandledMatchError extends Error
+ {
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php
new file mode 100644
index 0000000..783dbc2
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+ class ValueError extends Error
+ {
+ }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/bootstrap.php b/api_candidatos/vendor/symfony/polyfill-php80/bootstrap.php
new file mode 100644
index 0000000..e5f7dbc
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/bootstrap.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Php80 as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+ return;
+}
+
+if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
+ define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
+}
+
+if (!function_exists('fdiv')) {
+ function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
+}
+if (!function_exists('preg_last_error_msg')) {
+ function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
+}
+if (!function_exists('str_contains')) {
+ function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('str_starts_with')) {
+ function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('str_ends_with')) {
+ function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('get_debug_type')) {
+ function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
+}
+if (!function_exists('get_resource_id')) {
+ function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
+}
diff --git a/api_candidatos/vendor/symfony/polyfill-php80/composer.json b/api_candidatos/vendor/symfony/polyfill-php80/composer.json
new file mode 100644
index 0000000..a503b03
--- /dev/null
+++ b/api_candidatos/vendor/symfony/polyfill-php80/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "symfony/polyfill-php80",
+ "type": "library",
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.2"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
+ "files": [ "bootstrap.php" ],
+ "classmap": [ "Resources/stubs" ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}