Skip to content

Conversation

@R44VC0RP
Copy link
Owner

@R44VC0RP R44VC0RP commented Sep 1, 2025

…ient ID, and token structure. Improve error handling and streamline token management by utilizing SecurityManager methods.

Summary by CodeRabbit

  • New Features

    • Improved device login flow with clearer prompts and automatic browser opening (with fallback).
    • Fetches and stores user session after login and shows a welcome message.
    • Uses the complete verification URL when available for smoother sign-in.
  • Security

    • Validates base URL and client ID before starting auth.
    • Stronger token validation with expiration buffer and secure on-disk deletion.
    • Sanitized error messages to avoid leaking sensitive details.
  • Documentation

    • Added SECURITY guidelines covering OAuth 2.0 Device Flow, best practices, deployment, and testing.

…ient ID, and token structure. Improve error handling and streamline token management by utilizing SecurityManager methods.
@vercel
Copy link

vercel bot commented Sep 1, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
cursor.link Error Error Sep 1, 2025 8:34pm

@coderabbitai
Copy link

coderabbitai bot commented Sep 1, 2025

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ui-tweaks-and-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
cursor-link-cli/src/utils/auth-client.ts (2)

42-47: Set secure permissions on config directory (0700)

Prevents other users from listing token files.

   private ensureConfigDir() {
     if (!fs.existsSync(CONFIG_DIR)) {
-      fs.mkdirSync(CONFIG_DIR, { recursive: true });
+      fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
+    } else {
+      try { fs.chmodSync(CONFIG_DIR, 0o700); } catch {}
     }
   }

76-79: Persist tokens with 0600 perms and atomically

Avoid world-readable 0644 via umask defaults; use atomic rename.

   saveToken(tokenData: StoredToken) {
     this.ensureConfigDir();
-    fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokenData, null, 2));
+    const tmp = path.join(CONFIG_DIR, 'token.json.tmp');
+    const payload = JSON.stringify(tokenData, null, 2);
+    fs.writeFileSync(tmp, payload, { mode: 0o600 });
+    fs.renameSync(tmp, TOKEN_FILE);
   }
🧹 Nitpick comments (13)
cursor-link-cli/src/utils/security.ts (4)

41-52: Make token clearing more resilient

If chmod/write fails (permissions/AV), fall back to rm -f. Also prefer rmSync over unlinkSync.

       if (fs.existsSync(TOKEN_FILE)) {
-        // Overwrite with zeros before deletion (basic security)
+        // Overwrite with zeros before deletion (best-effort)
         const stats = fs.statSync(TOKEN_FILE);
         const zeros = Buffer.alloc(stats.size, 0);
-        fs.writeFileSync(TOKEN_FILE, zeros);
-        fs.unlinkSync(TOKEN_FILE);
+        try { fs.chmodSync(TOKEN_FILE, 0o600); } catch {}
+        try { fs.writeFileSync(TOKEN_FILE, zeros); } catch {}
+        fs.rmSync(TOKEN_FILE, { force: true });
       }
     } catch (error) {
-      console.warn('Warning: Could not securely clear token file:', error);
+      console.warn('Warning: Could not securely clear token file:', error);
+      try { fs.rmSync(TOKEN_FILE, { force: true }); } catch {}
     }

57-61: Client ID regex: avoid leading/trailing hyphen; consider underscores/dots if server allows

Current pattern allows "-" at ends and disallows "" or ".". Tighten ends and optionally allow [.].

-    const clientIdPattern = /^[a-zA-Z0-9-]{3,50}$/;
+    // Starts/ends with alnum; internal [-._] allowed. Adjust if server forbids _ or .
+    const clientIdPattern = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{1,48})[A-Za-z0-9]$/;

Please confirm allowed characters on the auth server before merging.


91-104: Nit: prefer error_description over terse error code

Show human-friendly descriptions first.

-    const safeFields = ['error', 'error_description', 'message'];
+    const safeFields = ['error_description', 'message', 'error'];

5-7: Avoid duplicating token path constants across modules

CONFIG_DIR/TOKEN_FILE are defined here and in auth-client.ts. Extract to a shared const/module to prevent drift.

cursor-link-cli/src/utils/auth-client.ts (6)

70-72: Self-heal on corrupt token file

If JSON.parse fails, clear the token to avoid repeated failures.

-      const sanitizedError = SecurityManager.sanitizeError(error);
-      console.error(`Error reading stored token: ${sanitizedError}`);
+      const sanitizedError = SecurityManager.sanitizeError(error);
+      console.error(`Error reading stored token: ${sanitizedError}`);
+      this.clearToken();
       return null;

121-129: Allow env override for client ID

Keeps defaults but enables testing/alternate clients.

-      const clientId = "cursor-link-cli";
+      const clientId = process.env.CURSOR_LINK_CLIENT_ID || "cursor-link-cli";

151-157: Prefer verification_uri_complete when present; only prompt for code if needed

Improves UX and matches OAuth device flow guidance.

-      console.log(chalk.cyan('\n📱 Device Authorization in Progress'));
-      console.log(chalk.white(`Please visit: ${verification_uri}`));
-      console.log(chalk.white(`Enter code: ${chalk.bold.yellow(user_code)}\n`));
+      console.log(chalk.cyan('\n📱 Device Authorization in Progress'));
+      const displayUrl = verification_uri_complete || verification_uri;
+      console.log(chalk.white(`Please visit: ${displayUrl}`));
+      if (!verification_uri_complete) {
+        console.log(chalk.white(`Enter code: ${chalk.bold.yellow(user_code)}\n`));
+      } else {
+        console.log();
+      }

156-164: Guard browser open against non-http(s) URLs

Be defensive with untrusted inputs.

-      const urlToOpen = verification_uri_complete || verification_uri;
+      const urlToOpen = verification_uri_complete || verification_uri;
       if (urlToOpen) {
-        console.log(chalk.gray('🌐 Opening browser...'));
-        try {
-          await open(urlToOpen);
+        console.log(chalk.gray('🌐 Opening browser...'));
+        try {
+          if (/^https?:\/\//i.test(urlToOpen)) {
+            await open(urlToOpen);
+          }
         } catch (error) {
           console.log(chalk.gray('Failed to open browser automatically. Please visit the URL manually.'));
         }
       }

267-271: Nit: avoid printing “undefined” when user fields are missing

Fallback gracefully to email or id.

-      if (token.user) {
-        console.log(chalk.gray(`   User: ${token.user.name} (${token.user.email})`));
-      }
+      if (token.user) {
+        const userLabel = token.user.name || token.user.email || token.user.id;
+        console.log(chalk.gray(`   User: ${userLabel}`));
+      }

12-14: De-duplicate token path constants

CONFIG_DIR/TOKEN_FILE are also defined in SecurityManager. Extract to a shared module (e.g., utils/paths.ts) and import from both to prevent drift.

cursor-link-cli/SECURITY.md (3)

50-57: Reflect URL validation hardening in docs

Mention that embedded credentials are blocked and ::1 is allowed in dev.

-// ✅ http://localhost:3000 - allowed in dev  
+// ✅ http://localhost:3000 - allowed in dev
+// ✅ http://[::1]:3000 - allowed in dev
 // ❌ http://malicious-site.com - blocked
+// ❌ https://user:pass@cursor.link - blocked (credentials in URL)

102-107: Document secure file/dir permissions

Clarify 0600/0700 to reduce leakage on multi-user systems.

-**Permissions**: File created with default user permissions
+**Permissions**: Directory 0700; token file 0600

95-117: Nit: minor Markdown/grammar tweaks for readability

Small fixes: remove double spaces for line breaks, standardize bullet punctuation, and tweak phrasing.

-### 1. Transport Security
-- **Production**: Requires HTTPS endpoints
-- **Development**: Allows localhost with HTTP
-- **Protection**: Prevents man-in-the-middle attacks
+### 1. Transport Security
+- **Production**: Require HTTPS endpoints.
+- **Development**: Allow localhost with HTTP.
+- **Protection**: Prevent man-in-the-middle attacks.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 22f1b4b and 7ca1d12.

📒 Files selected for processing (3)
  • cursor-link-cli/SECURITY.md (1 hunks)
  • cursor-link-cli/src/utils/auth-client.ts (7 hunks)
  • cursor-link-cli/src/utils/security.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/better-auth-device-authorization.mdc)

When calling device.token, set grant_type to "urn:ietf:params:oauth:grant-type:device_code"

Files:

  • cursor-link-cli/src/utils/security.ts
  • cursor-link-cli/src/utils/auth-client.ts
🧠 Learnings (2)
📚 Learning: 2025-09-01T20:24:00.229Z
Learnt from: CR
PR: R44VC0RP/cursor.link#0
File: .cursor/rules/better-auth-device-authorization.mdc:0-0
Timestamp: 2025-09-01T20:24:00.229Z
Learning: Applies to cli-auth.ts : In polling logic, handle OAuth device flow errors: continue on authorization_pending, increase interval on slow_down, and terminate on access_denied or expired_token

Applied to files:

  • cursor-link-cli/src/utils/auth-client.ts
📚 Learning: 2025-09-01T20:24:00.229Z
Learnt from: CR
PR: R44VC0RP/cursor.link#0
File: .cursor/rules/better-auth-device-authorization.mdc:0-0
Timestamp: 2025-09-01T20:24:00.229Z
Learning: Applies to **/*.{ts,tsx} : When calling device.token, set grant_type to "urn:ietf:params:oauth:grant-type:device_code"

Applied to files:

  • cursor-link-cli/src/utils/auth-client.ts
🧬 Code graph analysis (1)
cursor-link-cli/src/utils/auth-client.ts (1)
cursor-link-cli/src/utils/security.ts (1)
  • SecurityManager (12-105)
🪛 LanguageTool
cursor-link-cli/SECURITY.md

[grammar] ~46-~46: There might be a mistake here.
Context: ...}); ``` ### 🔒 Security Enhancements Our implementation adds these securi...

(QB_NEW_EN)


[grammar] ~88-~88: There might be a mistake here.
Context: ...vice Authorization Request (Section 3.1) - ✅ Device Authorization Response (Section...

(QB_NEW_EN)


[grammar] ~89-~89: There might be a mistake here.
Context: ...ice Authorization Response (Section 3.2) - ✅ User Interaction (Section 3.3) - ✅ Dev...

(QB_NEW_EN)


[grammar] ~90-~90: There might be a mistake here.
Context: ...3.2) - ✅ User Interaction (Section 3.3) - ✅ Device Access Token Request (Section 3...

(QB_NEW_EN)


[grammar] ~91-~91: There might be a mistake here.
Context: ...evice Access Token Request (Section 3.4) - ✅ Device Access Token Response (Section ...

(QB_NEW_EN)


[grammar] ~92-~92: There might be a mistake here.
Context: ...vice Access Token Response (Section 3.5) - ✅ Error Response Handling (Section 3.5.2...

(QB_NEW_EN)


[grammar] ~97-~97: There might be a mistake here.
Context: ...est Practices ### 1. Transport Security - Production: Requires HTTPS endpoints -...

(QB_NEW_EN)


[grammar] ~102-102: There might be a mistake here.
Context: ...-middle attacks ### 2. Token Management - Storage: Tokens stored in `
/.cursor-l...

(QB_NEW_EN)


[grammar] ~103-~103: There might be a mistake here.
Context: ...agement - Storage: Tokens stored in ~/.cursor-link/token.json - Permissions: File created with default...

(QB_NEW_EN)


[grammar] ~104-~104: There might be a mistake here.
Context: ...le created with default user permissions - Expiration: Tokens validated for expir...

(QB_NEW_EN)


[grammar] ~105-~105: There might be a mistake here.
Context: ...validated for expiration with 60s buffer - Cleanup: Secure deletion overwrites da...

(QB_NEW_EN)


[grammar] ~108-~108: There might be a mistake here.
Context: ...fore file removal ### 3. Error Handling - Sanitization: Error messages filtered ...

(QB_NEW_EN)


[grammar] ~113-~113: There might be a mistake here.
Context: ...tive data logged ### 4. Client Security - ID Validation: Client IDs must match s...

(QB_NEW_EN)


[grammar] ~123-~123: There might be a mistake here.
Context: ...HTTPS-only 2. Base URL: Defaults to https://cursor.link 3. Client ID: Uses cursor-link-cli (mus...

(QB_NEW_EN)


[grammar] ~154-~154: There might be a mistake here.
Context: ...Man-in-the-Middle: HTTPS enforcement 2. Token Theft: Secure file permissions &...

(QB_NEW_EN)


[grammar] ~155-~155: There might be a mistake here.
Context: ...eft**: Secure file permissions & cleanup 3. Phishing: URL validation prevents mali...

(QB_NEW_EN)


[grammar] ~156-~156: There might be a mistake here.
Context: ... validation prevents malicious redirects 4. Info Disclosure: Error message sanitiz...

(QB_NEW_EN)


[grammar] ~157-~157: There might be a mistake here.
Context: ...Disclosure**: Error message sanitization 5. Client Impersonation: Client ID valida...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Vade Review
🔇 Additional comments (3)
cursor-link-cli/src/utils/auth-client.ts (2)

18-23: Base URL validation at startup: LGTM

Good early exit with clear guidance.


185-188: Grant type is correctly set per guidelines

grant_type uses urn:ietf:params:oauth:grant-type:device_code. Compliant.

cursor-link-cli/SECURITY.md (1)

20-28: Docs: grant_type snippet matches our guideline

The example correctly sets grant_type to urn:ietf:params:oauth:grant-type:device_code.

Comment on lines +20 to +23
const requiredFields = ['access_token', 'expires_at'];
return requiredFields.every(field =>
token.hasOwnProperty(field) && token[field] != null
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: malformed expires_at can bypass expiry checks

validateToken only checks presence, so a non-numeric expires_at (e.g., "oops") passes validation. isTokenExpired will then compute Date.now() > ("oops" - 60000) ⇒ false, treating an invalid token as valid. Enforce types.

Apply:

   static validateToken(token: any): boolean {
-    if (!token || typeof token !== 'object') return false;
-    
-    // Required fields for a valid token
-    const requiredFields = ['access_token', 'expires_at'];
-    return requiredFields.every(field => 
-      token.hasOwnProperty(field) && token[field] != null
-    );
+    if (!token || typeof token !== 'object') return false;
+    const has = (o: any, k: string) => Object.prototype.hasOwnProperty.call(o, k);
+    if (!has(token, 'access_token') || !has(token, 'expires_at')) return false;
+    if (typeof token.access_token !== 'string' || token.access_token.trim().length === 0) return false;
+    if (typeof token.expires_at !== 'number' || !Number.isFinite(token.expires_at)) return false;
+    return true;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const requiredFields = ['access_token', 'expires_at'];
return requiredFields.every(field =>
token.hasOwnProperty(field) && token[field] != null
);
static validateToken(token: any): boolean {
if (!token || typeof token !== 'object') return false;
const has = (o: any, k: string) => Object.prototype.hasOwnProperty.call(o, k);
if (!has(token, 'access_token') || !has(token, 'expires_at')) return false;
if (typeof token.access_token !== 'string' || token.access_token.trim().length === 0) return false;
if (typeof token.expires_at !== 'number' || !Number.isFinite(token.expires_at)) return false;
return true;
}
🤖 Prompt for AI Agents
In cursor-link-cli/src/utils/security.ts around lines 20-23, validateToken
currently only checks for presence and allows non-numeric expires_at values;
update validateToken to require access_token be a non-empty string and
expires_at be a finite number (or a string that parses to an integer) — reject
if Number.isFinite(Number(token.expires_at)) is false or access_token is not a
string/empty. Also harden isTokenExpired to treat invalid or unparsable
expires_at as expired (return true) before doing the Date.now() comparison.

Comment on lines +29 to +35
static isTokenExpired(token: any): boolean {
if (!token.expires_at) return true;

// Add 60 second buffer to avoid edge cases
const bufferTime = 60 * 1000;
return Date.now() > (token.expires_at - bufferTime);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: guard isTokenExpired against non-numeric expires_at

Add strict type/finite checks so invalid tokens are treated as expired.

   static isTokenExpired(token: any): boolean {
-    if (!token.expires_at) return true;
-    
-    // Add 60 second buffer to avoid edge cases
-    const bufferTime = 60 * 1000;
-    return Date.now() > (token.expires_at - bufferTime);
+    if (typeof token?.expires_at !== 'number' || !Number.isFinite(token.expires_at)) {
+      return true;
+    }
+    const bufferTime = 60 * 1000;
+    return Date.now() > (token.expires_at - bufferTime);
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static isTokenExpired(token: any): boolean {
if (!token.expires_at) return true;
// Add 60 second buffer to avoid edge cases
const bufferTime = 60 * 1000;
return Date.now() > (token.expires_at - bufferTime);
}
static isTokenExpired(token: any): boolean {
if (typeof token?.expires_at !== 'number' || !Number.isFinite(token.expires_at)) {
return true;
}
const bufferTime = 60 * 1000;
return Date.now() > (token.expires_at - bufferTime);
}
🤖 Prompt for AI Agents
In cursor-link-cli/src/utils/security.ts around lines 29 to 35, the
isTokenExpired function should treat tokens with invalid or non-numeric
expires_at as expired; add a guard that checks typeof token.expires_at ===
'number' and Number.isFinite(token.expires_at) (or, if you want to accept
numeric strings, attempt Number(token.expires_at) and validate with
Number.isFinite) and return true immediately when the check fails, otherwise
proceed with the existing buffer calculation and comparison against Date.now().

Comment on lines +66 to +86
static validateBaseUrl(baseUrl: string): boolean {
try {
const url = new URL(baseUrl);

// In production, require HTTPS
if (process.env.NODE_ENV === 'production') {
return url.protocol === 'https:';
}

// In development, allow localhost with HTTP
if (url.protocol === 'http:' &&
(url.hostname === 'localhost' || url.hostname === '127.0.0.1')) {
return true;
}

// Otherwise require HTTPS
return url.protocol === 'https:';
} catch {
return false;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden URL validation: forbid embedded credentials; allow IPv6 loopback

Prevent auth endpoints like https://user:pass@host, and support ::1 in development.

   static validateBaseUrl(baseUrl: string): boolean {
     try {
       const url = new URL(baseUrl);
       
+      // Disallow embedded credentials
+      if (url.username || url.password) return false;
+
       // In production, require HTTPS
       if (process.env.NODE_ENV === 'production') {
         return url.protocol === 'https:';
       }
       
       // In development, allow localhost with HTTP
-      if (url.protocol === 'http:' && 
-          (url.hostname === 'localhost' || url.hostname === '127.0.0.1')) {
+      if (
+        url.protocol === 'http:' &&
+        (url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '::1')
+      ) {
         return true;
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static validateBaseUrl(baseUrl: string): boolean {
try {
const url = new URL(baseUrl);
// In production, require HTTPS
if (process.env.NODE_ENV === 'production') {
return url.protocol === 'https:';
}
// In development, allow localhost with HTTP
if (url.protocol === 'http:' &&
(url.hostname === 'localhost' || url.hostname === '127.0.0.1')) {
return true;
}
// Otherwise require HTTPS
return url.protocol === 'https:';
} catch {
return false;
}
}
static validateBaseUrl(baseUrl: string): boolean {
try {
const url = new URL(baseUrl);
// Disallow embedded credentials
if (url.username || url.password) return false;
// In production, require HTTPS
if (process.env.NODE_ENV === 'production') {
return url.protocol === 'https:';
}
// In development, allow localhost with HTTP
if (
url.protocol === 'http:' &&
(url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '::1')
) {
return true;
}
// Otherwise require HTTPS
return url.protocol === 'https:';
} catch {
return false;
}
}
🤖 Prompt for AI Agents
In cursor-link-cli/src/utils/security.ts around lines 66-86, the URL validation
must reject URLs that embed credentials and should treat IPv6 loopback as a
valid dev host; update validateBaseUrl to return false when url.username or
url.password are non-empty (to forbid user:pass@host), and in the development
branch allow HTTP if url.hostname is 'localhost', '127.0.0.1', or '::1'; keep
the production branch requiring url.protocol === 'https:' and preserve the
try/catch returning false on parse errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant