-
Notifications
You must be signed in to change notification settings - Fork 412
fix: Refactor isURL() to use Built-in URL Constructor
#3061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,8 +15,6 @@ | |
| * limitations under the License. | ||
| */ | ||
|
|
||
| import url = require('url'); | ||
|
|
||
| /** | ||
| * Validates that a value is a byte buffer. | ||
| * | ||
|
|
@@ -234,33 +232,38 @@ export function isURL(urlStr: any): boolean { | |
| return false; | ||
| } | ||
| try { | ||
| const uri = url.parse(urlStr); | ||
| const uri = new URL(urlStr); | ||
| const scheme = uri.protocol; | ||
| const slashes = uri.slashes; | ||
| const hostname = uri.hostname; | ||
| const pathname = uri.pathname; | ||
| if ((scheme !== 'http:' && scheme !== 'https:') || !slashes) { | ||
| if (scheme !== 'http:' && scheme !== 'https:') { | ||
| return false; | ||
| } | ||
| // Validate hostname: Can contain letters, numbers, underscore and dashes separated by a dot. | ||
| // Each zone must not start with a hyphen or underscore. | ||
| if (!hostname || !/^[a-zA-Z0-9]+[\w-]*([.]?[a-zA-Z0-9]+[\w-]*)*$/.test(hostname)) { | ||
| return false; | ||
| const hostname = uri.hostname; | ||
| // Validate hostname strictly to match previous behavior and prevent weak/invalid domains. | ||
| // Must be alphanumeric with optional dashes/underscores, separated by dots. | ||
| // Cannot start/end with dot or dash (mostly). | ||
| // This regex is safe (no nested quantifiers with overlap). | ||
| if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/.test(hostname)) { | ||
| // Check for IPv6 literals which are valid but behave differently. | ||
| // Node 'new URL' keeps brackets for IPv6: [::1] -> [::1] | ||
| // Check for IPv6 address (simple check for brackets) | ||
| if (!/^\[[a-fA-F0-9:.]+\]$/.test(hostname)) { | ||
| return false; | ||
| } | ||
| } | ||
|
Comment on lines
+245
to
252
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The nested const isValidDomain = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/.test(hostname);
// An IPv6 literal is enclosed in brackets. `new URL()` has already validated the contents.
const isIPv6Literal = /^\[[a-fA-F0-9:.]+\]$/.test(hostname);
if (!isValidDomain && !isIPv6Literal) {
return false;
} |
||
| // Allow for pathnames: (/chars+)*/? | ||
| // Restore strict pathname validation: (/chars+)*/? | ||
| // Where chars can be a combination of: a-z A-Z 0-9 - _ . ~ ! $ & ' ( ) * + , ; = : @ % | ||
| const pathnameRe = /^(\/[\w\-.~!$'()*+,;=:@%]+)*\/?$/; | ||
| // Validate pathname. | ||
| const pathname = uri.pathname; | ||
| if (pathname && | ||
| pathname !== '/' && | ||
| !pathnameRe.test(pathname)) { | ||
| pathname !== '/' && | ||
| !pathnameRe.test(pathname)) { | ||
| return false; | ||
| } | ||
| // Allow any query string and hash as long as no invalid character is used. | ||
| return true; | ||
lahirumaramba marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } catch (e) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.