UNPKG

@hellocoop/web-identity

Version:

Functions for generating and verifying JWT tokens used in the Verified Email Autocomplete protocol

154 lines 4.42 kB
import { JWKValidationError } from '../errors.js'; import { createHash } from 'crypto'; /** * Validates that a JWK contains required fields for the specified algorithm * @param jwk - JSON Web Key to validate * @returns void (throws on validation failure) */ export function validateJWK(jwk) { if (!jwk.alg) { throw new JWKValidationError('JWK must contain "alg" field'); } if (!jwk.kid) { throw new JWKValidationError('JWK must contain "kid" field'); } if (!jwk.kty) { throw new JWKValidationError('JWK must contain "kty" field'); } // Validate algorithm-specific parameters switch (jwk.kty) { case 'RSA': validateRSAKey(jwk); break; case 'EC': validateECKey(jwk); break; case 'OKP': validateOKPKey(jwk); break; default: throw new JWKValidationError(`Unsupported key type: ${jwk.kty}`); } } /** * Validates RSA key parameters */ function validateRSAKey(jwk) { if (!jwk.n) { throw new JWKValidationError('RSA key must contain "n" parameter'); } if (!jwk.e) { throw new JWKValidationError('RSA key must contain "e" parameter'); } } /** * Validates Elliptic Curve key parameters */ function validateECKey(jwk) { if (!jwk.crv) { throw new JWKValidationError('EC key must contain "crv" parameter'); } if (!jwk.x) { throw new JWKValidationError('EC key must contain "x" parameter'); } if (!jwk.y) { throw new JWKValidationError('EC key must contain "y" parameter'); } } /** * Validates Octet Key Pair parameters (EdDSA) */ function validateOKPKey(jwk) { if (!jwk.crv) { throw new JWKValidationError('OKP key must contain "crv" parameter'); } if (!jwk.x) { throw new JWKValidationError('OKP key must contain "x" parameter'); } // Validate supported curves if (jwk.crv !== 'Ed25519' && jwk.crv !== 'Ed448' && jwk.crv !== 'X25519' && jwk.crv !== 'X448') { throw new JWKValidationError(`Unsupported OKP curve: ${jwk.crv}`); } } /** * Extracts only the public key parameters from a JWK for inclusion in cnf claims * Removes private key material (d parameter) and other sensitive information * @param jwk - Source JWK (may contain private key) * @returns JWK with only public key parameters */ export function extractPublicKeyParameters(jwk) { const publicJwk = { kty: jwk.kty, alg: jwk.alg, kid: jwk.kid, }; switch (jwk.kty) { case 'RSA': publicJwk.n = jwk.n; publicJwk.e = jwk.e; break; case 'EC': publicJwk.crv = jwk.crv; publicJwk.x = jwk.x; publicJwk.y = jwk.y; break; case 'OKP': publicJwk.crv = jwk.crv; publicJwk.x = jwk.x; break; } return publicJwk; } /** * Calculates SHA-256 hash of a string * @param input - String to hash * @returns Base64url-encoded hash */ export function calculateSHA256Hash(input) { const hash = createHash('sha256'); hash.update(input); return hash.digest('base64url'); } /** * Validates email address syntax * @param email - Email address to validate * @returns true if valid, false otherwise */ export function isValidEmail(email) { // Basic format check const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return false; } // Security checks for malicious content const maliciousPatterns = [ /<[^>]*>/, // HTML tags /[\r\n]/, // Line breaks (CRLF injection) /\0/, // Null bytes /\.\./, // Path traversal /javascript:/i, // JavaScript protocol /data:/i, // Data protocol /vbscript:/i, // VBScript protocol /%[0-9a-f]{2}/i, // URL encoding (potential bypass) ]; for (const pattern of maliciousPatterns) { if (pattern.test(email)) { return false; } } // Length checks if (email.length > 254) { // RFC 5321 limit return false; } const [localPart, domainPart] = email.split('@'); if (localPart.length > 64 || domainPart.length > 253) { // RFC 5321 limits return false; } return true; } //# sourceMappingURL=crypto.js.map