UNPKG

@reown/appkit-controllers

Version:

The full stack toolkit to build onchain app UX.

158 lines 5.52 kB
/** * Parses a string as a URL. * @param value - The string to parse. * @returns The parsed URL object or null if invalid. */ export function parseUrl(value) { try { return new URL(value); } catch { return null; } } /** * Parses a schemeless host:port pattern from a string. * @param pattern - The input pattern string. * @returns An object containing the host and optional port. */ export function parseSchemelessHostPort(pattern) { const parts = pattern.split('/'); const withoutPath = parts.length > 0 && parts[0] !== undefined ? parts[0] : ''; const lastColon = withoutPath.lastIndexOf(':'); if (lastColon === -1) { return { host: withoutPath }; } return { host: withoutPath.slice(0, lastColon), port: withoutPath.slice(lastColon + 1) }; } /** * Parses an origin string into its scheme, host, and optional port. * @param origin - The origin string to parse. * @returns An object with scheme, host, and optional port, or null if invalid. */ export function parseOriginRaw(origin) { const schemeIdx = origin.indexOf('://'); if (schemeIdx === -1) { return null; } const scheme = origin.slice(0, schemeIdx); const start = schemeIdx + 3; let end = origin.indexOf('/', start); if (end === -1) { end = origin.length; } const hostPort = origin.slice(start, end); const lastColon = hostPort.lastIndexOf(':'); if (lastColon === -1) { return { scheme, host: hostPort }; } return { scheme, host: hostPort.slice(0, lastColon), port: hostPort.slice(lastColon + 1) }; } /** * Checks if the current origin matches a non-wildcard pattern. * @param currentOrigin - The current origin as a string. * @param pattern - The pattern string to match. * @returns True if the pattern matches, otherwise false. */ export function matchNonWildcardPattern(currentOrigin, pattern) { // If pattern explicitly specifies a scheme, compare origins (ignore path) if (pattern.includes('://')) { const url = parseUrl(pattern); return url ? url.origin === currentOrigin : false; } // Schemeless: treat as hostname[:port] const { host, port } = parseSchemelessHostPort(pattern); // Extract raw host[:port] from the origin string to preserve case-sensitivity const schemeIdx = currentOrigin.indexOf('://'); if (schemeIdx !== -1) { const start = schemeIdx + 3; let end = currentOrigin.indexOf('/', start); if (end === -1) { end = currentOrigin.length; } const rawHostPort = currentOrigin.slice(start, end); if (port !== undefined) { return `${host}:${port}` === rawHostPort; } const rawHostOnly = rawHostPort.split(':')[0]; return host === rawHostOnly; } // Fallback to URL parsing when origin isn't a standard scheme URL const current = parseUrl(currentOrigin); if (!current) { return false; } if (port !== undefined) { return host === current.hostname && port === (current.port || undefined); } return host === current.hostname; } /** * Checks if the current origin matches a wildcard pattern. * @param current - The current origin as a URL object. * @param currentOrigin - The current origin as a string. * @param pattern - The wildcard pattern string to use. * @returns True if matches the wildcard pattern, otherwise false. */ export function matchWildcardPattern(current, currentOrigin, pattern) { // Extract scheme if present and strip path let working = pattern; let scheme = undefined; const schemeIdx = working.indexOf('://'); if (schemeIdx !== -1) { scheme = working.slice(0, schemeIdx); working = working.slice(schemeIdx + 3); } const slashIdx = working.indexOf('/'); if (slashIdx !== -1) { working = working.slice(0, slashIdx); } // Split host and optional port let hostPart = working; let portPart = undefined; const lastColon = hostPart.lastIndexOf(':'); if (lastColon !== -1) { portPart = hostPart.slice(lastColon + 1); hostPart = hostPart.slice(0, lastColon); } // Validate wildcard usage (only full-label '*') const patternLabels = hostPart.split('.'); for (const label of patternLabels) { if (label.includes('*') && label !== '*') { return false; } } // Scheme must match when specified const currentScheme = current.protocol.replace(/:$/u, ''); if (scheme && scheme !== currentScheme) { return false; } // Port must match exactly when specified (or '*' allows any) if (portPart !== undefined) { if (portPart !== '*' && portPart !== current.port) { return false; } } /** * Host must have the same number of labels; '*' matches exactly one label. * Uses raw host from the original origin to preserve case-sensitivity. */ const raw = parseOriginRaw(currentOrigin); const hostForCompare = raw ? raw.host : current.hostname; const currentLabels = hostForCompare.split('.'); if (patternLabels.length !== currentLabels.length) { return false; } for (let i = patternLabels.length - 1; i >= 0; i -= 1) { const p = patternLabels[i]; const c = currentLabels[i]; if (p !== '*' && p !== c) { return false; } } return true; } //# sourceMappingURL=UrlUtils.js.map