Skip to content
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

fix: Short url fixes #4773

Merged
merged 9 commits into from
Oct 14, 2024
Merged

fix: Short url fixes #4773

merged 9 commits into from
Oct 14, 2024

Conversation

Subhra264
Copy link
Contributor

@Subhra264 Subhra264 commented Oct 14, 2024

Fixes #4757

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced authentication handling with improved validation and request processing.
    • Introduced a builder pattern for constructing redirect responses, allowing for optional query parameters.
    • Updated URL shortening and retrieval processes to support organization-specific identifiers.
  • Bug Fixes

    • Improved error handling for JSON deserialization in URL shortening.
    • Fixed issues with alert name validation logic.
  • Documentation

    • Minor adjustments made to comments and documentation for clarity.
  • Tests

    • Added tests to verify new functionalities and ensure robustness.

Copy link
Contributor

coderabbitai bot commented Oct 14, 2024

Walkthrough

The changes primarily involve enhancements to authentication and URL handling across various modules. The AuthExtractor struct has been improved to better manage authorization checks, particularly for enterprise features. The RedirectResponse struct has been updated to include query parameters and now uses a builder pattern for instantiation. Additionally, multiple functions related to URL shortening and retrieval have been modified to include an org_id parameter, improving their functionality. Overall, these changes aim to streamline request handling and enhance the user experience with short URLs.

Changes

File Path Change Summary
src/common/utils/auth.rs Enhanced AuthExtractor and from_request method with new conditions for authorization handling.
src/common/utils/redirect_response.rs Updated RedirectResponse struct to include query parameters; replaced constructor with builder pattern.
src/handler/http/auth/validator.rs Improved authentication validation; added new helper functions for path extraction and URL handling.
src/handler/http/request/short_url/mod.rs Updated shorten and retrieve functions to include org_id in signatures and error handling.
src/handler/http/router/mod.rs Modified routing logic to conditionally include middleware based on enterprise feature flag.
src/service/alerts/alert.rs Updated send_notification to include org_id in alert URL generation; added a new test case.
src/service/dashboards/reports.rs Updated generate_report to pass org_id to short_url::shorten.
src/service/short_url.rs Enhanced short URL service with org_id parameter in multiple functions; added construct_short_url.
web/src/router/index.ts Refined redirect logic for unauthenticated users; improved readability of conditions.

Assessment against linked issues

Objective Addressed Explanation
Ensure users are redirected correctly after logging in with SSO for shared links. No changes related to SSO redirection handling.
Handle invalid URLs gracefully when logging in with SSO.
Ensure timezone information is displayed correctly in alerts when accessed via SSO. Unclear if timezone handling was addressed.

Possibly related PRs

Suggested labels

☢️ Bug, 🧹 Updates

Suggested reviewers

  • bjp232004
  • hengfeiyang

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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.

@github-actions github-actions bot added the ☢️ Bug Something isn't working label Oct 14, 2024
@Subhra264 Subhra264 requested review from bjp232004, oasisk and Loaki07 and removed request for bjp232004 October 14, 2024 07:02
Copy link
Contributor

@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: 10

🧹 Outside diff range and nitpick comments (7)
web/src/router/index.ts (3)

Line range hint 81-89: Consider adding error handling for invalid URLs.

To address the issue of "Short URL not found" errors mentioned in the PR objectives, consider adding error handling logic here. This could involve checking the validity of the short_url before storing it and providing appropriate feedback to the user.

Here's a suggested implementation:

if (Object.hasOwn(to.query, "short_url")) {
  const shortUrl = to.query.short_url as string;
  if (isValidShortUrl(shortUrl)) {
    window.sessionStorage.setItem("redirectURI", shortUrl);
  } else {
    // Handle invalid short URL
    console.error("Invalid short URL");
    // Optionally, redirect to an error page or show a notification
  }
} else {
  window.sessionStorage.setItem("redirectURI", window.location.href);
}

// Add this function to validate the short URL
function isValidShortUrl(url: string): boolean {
  // Implement validation logic here
  // For example, check if it matches a specific pattern or exists in your database
  return true; // Placeholder return
}

81-85: Add comments to explain short URL handling.

To improve code maintainability, consider adding comments to explain the purpose and functionality of the short_url handling. This will help future developers understand the logic behind this implementation.

Here's a suggested comment:

// Handle short URL redirection
// If the query params contain a short_url, store it in session storage
// This is used to redirect the user to the correct page after authentication
// particularly when accessing shared log search links
if (Object.hasOwn(to.query, "short_url")) {
  window.sessionStorage.setItem("redirectURI", to.query.short_url);
}

Line range hint 74-89: Overall assessment of changes

The changes in this file improve code readability and maintain the existing functionality. However, they don't fully address the specific issues mentioned in the PR objectives, such as problems with incognito mode, SSO, and invalid URL handling.

To fully meet the PR objectives:

  1. Implement specific handling for incognito mode and SSO scenarios.
  2. Add error handling for invalid short URLs.
  3. Address the timezone display issue mentioned in the PR objectives.

Consider adding more comprehensive changes to tackle these issues directly.

src/service/alerts/alert.rs (2)

Line range hint 616-815: Consider refactoring process_dest_template for improved maintainability

While the function is working as intended, its length and complexity make it a candidate for refactoring. Consider the following suggestions:

  1. Extract the URL generation logic into separate functions for PromQL and SQL/Custom queries.
  2. Create a dedicated function for variable replacement to reduce code duplication.
  3. Use a struct to hold the alert context (start time, end time, etc.) instead of passing multiple parameters.

These changes could improve readability and make the function easier to maintain and test.

Would you like me to provide a sample refactored structure for this function?


Line range hint 1-815: Consider additional security measures

While the code generally handles security well, consider the following improvements:

  1. In the send_http_notification function, ensure that the skip_tls_verify option is used cautiously and only in controlled environments.
  2. When processing user-provided templates and variables, consider implementing additional sanitization to prevent potential XSS or template injection attacks.
  3. In the send_email_notification function, consider adding rate limiting to prevent potential abuse of the email sending functionality.
  4. Review the error messages returned to ensure they don't leak sensitive information.

Implementing these suggestions could further enhance the security of the alert system.

Would you like me to provide code snippets for implementing any of these security improvements?

src/handler/http/request/short_url/mod.rs (1)

115-116: Enhance error logging for better debugging

Logging the redirect object may not provide meaningful information when a short URL is not found. Consider logging the short_id to assist with debugging.

Apply this diff:

- log::error!("Short URL not found, {}", &redirect);
+ log::error!("Short URL not found for short_id: {}", short_id);
src/service/short_url.rs (1)

Line range hint 64-91: Update retrieve function to consider org_id

The retrieve function doesn't include org_id when fetching the original URL. This might result in retrieving the wrong URL if the same short_id exists across different organizations.

Modify retrieve to accept org_id and use it in the retrieval process:

-pub async fn retrieve(short_id: &str) -> Option<String> {
-    db::short_url::get(short_id).await.ok()
+pub async fn retrieve(org_id: &str, short_id: &str) -> Option<String> {
+    let key = format!("{}:{}", org_id, short_id);
+    db::short_url::get(&key).await.ok()
 }

Adjust calls to retrieve throughout the codebase and update the database functions to handle the composite key.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ad6845c and d9b0f9a.

📒 Files selected for processing (9)
  • src/common/utils/auth.rs (1 hunks)
  • src/common/utils/redirect_response.rs (2 hunks)
  • src/handler/http/auth/validator.rs (3 hunks)
  • src/handler/http/request/short_url/mod.rs (4 hunks)
  • src/handler/http/router/mod.rs (1 hunks)
  • src/service/alerts/alert.rs (1 hunks)
  • src/service/dashboards/reports.rs (1 hunks)
  • src/service/short_url.rs (5 hunks)
  • web/src/router/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
src/common/utils/auth.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/common/utils/redirect_response.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/handler/http/auth/validator.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/handler/http/request/short_url/mod.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/handler/http/router/mod.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/service/alerts/alert.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/service/dashboards/reports.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

src/service/short_url.rs (1)

Pattern **/*.rs: You are a smart rustlang pull request reviewer.
You are going to review all the rustlang files.
Be concise, and add a brief explanation to your suggestions

Make sure the responses are not too verbose and keep the suggestions to the point i.e. actionable.

🔇 Additional comments (18)
web/src/router/index.ts (2)

74-78: Improved readability of path checking conditions.

The expansion of the path checking conditions into a multi-line format enhances code readability and maintainability. This change is a positive step towards cleaner code.


Line range hint 74-89: Clarification needed on addressing PR objectives.

While the changes improve the code structure, it's not immediately clear how they address the specific issues mentioned in the PR objectives, such as:

  1. Redirection problems in incognito mode with SSO.
  2. Handling of "Short URL not found" errors.
  3. Timezone display issues in SSO and incognito mode.

Could you please clarify how these changes relate to resolving these specific problems?

src/service/dashboards/reports.rs (1)

621-621: LGTM! Verify short URL functionality across the application.

The addition of org_id to the short_url::shorten function call aligns with the PR objectives and should help resolve the issues with sharing log search links. This change appears to be correct and consistent.

To ensure this change doesn't introduce any regressions, please run the following verification script:

✅ Verification successful

Verified: All short_url::shorten calls include org_id as the first argument.

No issues found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all calls to short_url::shorten now include org_id as the first argument.

# Test: Search for all occurrences of short_url::shorten. Expect: All calls should include org_id as the first argument.
rg --type rust 'short_url::shorten\s*\(' -A 2

Length of output: 782

src/service/alerts/alert.rs (3)

Line range hint 1-815: Overall assessment: Good implementation with room for improvements

The alert system implementation is generally well-structured and functional. The recent change to include org_id in short URL generation is a positive improvement. However, there are opportunities for enhancing the code:

  1. Refactor large functions like process_dest_template and save for better maintainability.
  2. Address the commented-out alert evaluation code in the save function.
  3. Implement additional security measures as suggested.
  4. Consider adding more comprehensive error handling and logging throughout the file.

These improvements would make the code more robust, maintainable, and secure.


Line range hint 807-815: LGTM: Short URL generation for alert URLs

The change to include the org_id in the short_url::shorten function call is a good improvement. This ensures that short URLs are organization-specific, which is important for multi-tenant systems.

To ensure this change is consistent across the codebase, let's verify other usages of short_url::shorten:

✅ Verification successful

Consistency of short_url::shorten Usage Confirmed

All instances of short_url::shorten across the codebase now include the org_id parameter, ensuring consistent and organization-specific URL shortening.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other usages of short_url::shorten to ensure consistency
rg --type rust "short_url::shorten\(" -C 3

Length of output: 98


Script:

#!/bin/bash
# Description: Verify all usages of short_url::shorten to ensure consistency
rg --type rust 'short_url::shorten\s*\(' -C 3

Length of output: 1558


Line range hint 78-196: Address commented-out alert evaluation code

There's a commented-out section for alert evaluation in the save function. This raises a few concerns:

  1. If this code is no longer needed, it should be removed to avoid confusion.
  2. If it's still relevant but causing issues (as the comment suggests), consider refactoring it to handle large data volumes more efficiently.
  3. If it's a temporary measure, add a TODO comment explaining why it's commented out and when it should be re-enabled.

Additionally, consider breaking down this large function into smaller, more focused functions to improve readability and maintainability.

Let's check if there are any related TODO comments or issues:

src/service/short_url.rs (1)

Line range hint 112-135: Adjust tests to reflect changes in org_id handling

Ensure that test cases account for the updated storage and retrieval mechanisms involving org_id. This will verify that the functions work correctly with the new logic.

Update the test functions to use the modified retrieve function and check for organization-specific behavior.

src/common/utils/redirect_response.rs (1)

74-101: Good use of builder pattern for constructing redirect responses

The introduction of RedirectResponseBuilder enhances flexibility and readability in constructing RedirectResponse instances.

src/common/utils/auth.rs (1)

409-409: ⚠️ Potential issue

Potential Security Risk: Bypassing Permission Checks for /short Paths

Adding || path.contains("/short") to the condition means that any request with /short in its path will bypass permission checks (bypass_check: true). This could unintentionally allow unauthorized access to protected resources if other endpoints contain /short in their paths. Please verify that this change does not introduce security vulnerabilities and consider making the condition more specific to the intended endpoint.

Run the following script to identify all routes containing /short to assess potential security implications:

src/handler/http/auth/validator.rs (9)

36-36: Importing RedirectResponseBuilder is appropriate

The addition of redirect_response::RedirectResponseBuilder is necessary for handling redirect responses in authentication failures, enhancing the redirect functionality.


647-647: Updating oo_validator function signature improves error handling

Changing the oo_validator function to accept Result<AuthExtractor, Error> allows for better handling of authentication extraction errors directly within the function.


650-652: Extracting relative path and identifying short URLs

The introduction of extract_relative_path and is_short_url_path functions helps in accurately determining if a request is for a short URL, which is crucial for conditional error handling.


654-663: Handling authentication extraction errors for short URLs

The modified error handling appropriately differentiates between short URLs and other paths. If authentication extraction fails for a short URL, the user is redirected, improving the user experience.


665-671: Conditional error handling after internal validation

By checking is_short_url after oo_validator_internal, the code ensures that authentication failures for short URLs result in a redirect response, while other paths receive standard error handling.


802-810: New helper function extract_relative_path enhances path handling

The extract_relative_path function efficiently removes the base URI and path prefix, simplifying the extraction of the relative path for further processing.


812-817: New helper function is_short_url_path accurately detects short URL paths

The is_short_url_path function correctly identifies short URL requests by checking the second segment of the path, which is essential for custom authentication handling.


825-836: Redirecting on authentication failure for short URLs

The handle_auth_failure_for_redirect function constructs a redirect response when authentication fails on short URLs. Including the original URL as a query parameter facilitates user redirection post-authentication.


838-850: Function extract_full_url correctly constructs the complete request URL

The extract_full_url function accurately assembles the full URL, including the scheme, host, path, and query parameters, which is essential for redirecting users back to their intended destination after authentication.

pub async fn shorten(org_id: web::Path<String>, body: web::Bytes) -> Result<HttpResponse, Error> {
let req: config::meta::short_url::ShortenUrlRequest = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(e) => return Ok(MetaHttpResponse::bad_request(e)),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid exposing internal error details in responses

Returning the raw deserialization error e to the client may leak internal implementation details. Consider returning a generic error message to prevent potential information disclosure.

Apply this diff to fix:

- Err(e) => return Ok(MetaHttpResponse::bad_request(e)),
+ Err(_) => return Ok(MetaHttpResponse::bad_request("Invalid request body")),
📝 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
Err(e) => return Ok(MetaHttpResponse::bad_request(e)),
Err(_) => return Ok(MetaHttpResponse::bad_request("Invalid request body")),

Comment on lines +73 to +78
Ok(
HttpResponse::InternalServerError().json(meta::http::HttpResponse::error(
StatusCode::INTERNAL_SERVER_ERROR.into(),
e.to_string(),
)),
)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid including internal error messages in HTTP responses

Exposing internal error messages (e.to_string()) in the HTTP response body may reveal sensitive information. It's better to return a generic error message to the client.

Apply this diff to fix:

- Ok(
-     HttpResponse::InternalServerError().json(meta::http::HttpResponse::error(
-         StatusCode::INTERNAL_SERVER_ERROR.into(),
-         e.to_string(),
-     )),
- )
+ Ok(
+     HttpResponse::InternalServerError().json(meta::http::HttpResponse::error(
+         StatusCode::INTERNAL_SERVER_ERROR.into(),
+         "Internal server error".to_string(),
+     )),
+ )
📝 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
Ok(
HttpResponse::InternalServerError().json(meta::http::HttpResponse::error(
StatusCode::INTERNAL_SERVER_ERROR.into(),
e.to_string(),
)),
)
Ok(
HttpResponse::InternalServerError().json(meta::http::HttpResponse::error(
StatusCode::INTERNAL_SERVER_ERROR.into(),
"Internal server error".to_string(),
)),
)

) -> Result<HttpResponse, Error> {
log::info!(
"short_url::retrieve handler called for path: {}",
req.path()
);
let short_id = short_id.into_inner();
let (_org_id, short_id) = path.into_inner();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use org_id to enforce authorization and data isolation

The org_id parameter is extracted but not used, which can lead to security issues by potentially allowing access to short URLs across organizations. Ensure that org_id is used to retrieve the short URL, enforcing proper authorization.

Apply this diff to fix:

- let (_org_id, short_id) = path.into_inner();
- let original_url = short_url::retrieve(&short_id).await;
+ let (org_id, short_id) = path.into_inner();
+ let original_url = short_url::retrieve(&org_id, &short_id).await;

And update the retrieve function in the short_url service to accept org_id and enforce authorization accordingly.

Committable suggestion was skipped due to low confidence.

Comment on lines +32 to +41
fn construct_short_url(org_id: &str, short_id: &str) -> String {
format!(
"{}/{}/{}{}{}",
get_base_url(),
"api",
org_id,
SHORT_URL_WEB_PATH,
short_id
))
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure correct URL formatting in construct_short_url

The format string in construct_short_url may result in an incorrect URL due to missing slashes between components. Specifically, there might be a missing slash between "api" and org_id, which could lead to malformed URLs.

Consider updating the format string to properly include slashes between all parts of the URL. For example:

 fn construct_short_url(org_id: &str, short_id: &str) -> String {
     format!(
-        "{}/{}/{}{}{}",
+        "{}/{}/{}/{}{}",
         get_base_url(),
         "api",
         org_id,
         SHORT_URL_WEB_PATH,
         short_id
     )
 }
📝 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
fn construct_short_url(org_id: &str, short_id: &str) -> String {
format!(
"{}/{}/{}{}{}",
get_base_url(),
"api",
org_id,
SHORT_URL_WEB_PATH,
short_id
))
)
}
fn construct_short_url(org_id: &str, short_id: &str) -> String {
format!(
"{}/{}/{}/{}{}",
get_base_url(),
"api",
org_id,
SHORT_URL_WEB_PATH,
short_id
)
}

Comment on lines +103 to +106
fn get_short_id_from_url(org_id: &str, short_url: &str) -> Option<String> {
let prefix = format!("{}api/{}{}", get_base_url(), org_id, SHORT_URL_WEB_PATH);
short_url.strip_prefix(&prefix).map(|s| s.to_string())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the URL prefix in get_short_id_from_url

The format string for prefix in get_short_id_from_url may be missing a slash between "api" and org_id, potentially causing incorrect extraction of short_id.

Revise the format string to include the missing slash:

 fn get_short_id_from_url(org_id: &str, short_url: &str) -> Option<String> {
-    let prefix = format!("{}api/{}{}", get_base_url(), org_id, SHORT_URL_WEB_PATH);
+    let prefix = format!("{}api/{}/{}{}", get_base_url(), org_id, SHORT_URL_WEB_PATH);
     short_url.strip_prefix(&prefix).map(|s| s.to_string())
 }
📝 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
fn get_short_id_from_url(org_id: &str, short_url: &str) -> Option<String> {
let prefix = format!("{}api/{}{}", get_base_url(), org_id, SHORT_URL_WEB_PATH);
short_url.strip_prefix(&prefix).map(|s| s.to_string())
}
fn get_short_id_from_url(org_id: &str, short_url: &str) -> Option<String> {
let prefix = format!("{}api/{}/{}{}", get_base_url(), org_id, SHORT_URL_WEB_PATH);
short_url.strip_prefix(&prefix).map(|s| s.to_string())
}

Comment on lines +43 to +50
async fn store_short_url(
org_id: &str,
short_id: &str,
original_url: &str,
) -> Result<String, anyhow::Error> {
let entry = ShortUrlRecord::new(short_id, original_url);
db::short_url::set(short_id, entry).await?;
Ok(construct_short_url(org_id, short_id))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Associate org_id with stored short URLs in the database

The store_short_url function accepts org_id, but it doesn't use it when storing the short URL. This could lead to conflicts if different organizations generate the same short_id, as the short_id is used as the key without considering org_id.

Modify the storage function to include org_id when storing the short URL to ensure uniqueness per organization. For example:

 fn store_short_url(
     org_id: &str,
     short_id: &str,
     original_url: &str,
 ) -> Result<String, anyhow::Error> {
     let entry = ShortUrlRecord::new(short_id, original_url);
-    db::short_url::set(short_id, entry).await?;
+    let key = format!("{}:{}", org_id, short_id);
+    db::short_url::set(&key, entry).await?;
     Ok(construct_short_url(org_id, short_id))
 }

Ensure that the retrieval function and database schema are updated accordingly.

📝 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
async fn store_short_url(
org_id: &str,
short_id: &str,
original_url: &str,
) -> Result<String, anyhow::Error> {
let entry = ShortUrlRecord::new(short_id, original_url);
db::short_url::set(short_id, entry).await?;
Ok(construct_short_url(org_id, short_id))
async fn store_short_url(
org_id: &str,
short_id: &str,
original_url: &str,
) -> Result<String, anyhow::Error> {
let entry = ShortUrlRecord::new(short_id, original_url);
let key = format!("{}:{}", org_id, short_id);
db::short_url::set(&key, entry).await?;
Ok(construct_short_url(org_id, short_id))

Comment on lines +38 to +45
let query_string: String = self
.query_params
.iter()
.map(|(key, value)| format!("{}={}", key, value))
.collect::<Vec<String>>()
.join("&");

redirect_uri = format!("{}?{}", redirect_uri, query_string);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure query parameters are URL-encoded

When constructing the query string, keys and values should be URL-encoded to handle special characters correctly. Currently, keys and values are not encoded, which can lead to malformed URLs if they contain characters that need to be percent-encoded.

Apply this diff to URL-encode the query parameters:

+use url::form_urlencoded::Serializer;

...

-                let query_string: String = self
-                    .query_params
-                    .iter()
-                    .map(|(key, value)| format!("{}={}", key, value))
-                    .collect::<Vec<String>>()
-                    .join("&");
+                let mut serializer = url::form_urlencoded::Serializer::new(String::new());
+                for (key, value) in &self.query_params {
+                    serializer.append_pair(key, value);
+                }
+                let query_string = serializer.finish();

You may need to add the url crate to your dependencies in Cargo.toml if it's not already included.

📝 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
let query_string: String = self
.query_params
.iter()
.map(|(key, value)| format!("{}={}", key, value))
.collect::<Vec<String>>()
.join("&");
redirect_uri = format!("{}?{}", redirect_uri, query_string);
use url::form_urlencoded::Serializer;
let mut serializer = url::form_urlencoded::Serializer::new(String::new());
for (key, value) in &self.query_params {
serializer.append_pair(key, value);
}
let query_string = serializer.finish();
redirect_uri = format!("{}?{}", redirect_uri, query_string);

Comment on lines +165 to +168
let expected_uri =
"/web?redirect_url=http://localhost:5080/api/default/short/1234&user_id=42";
assert_eq!(redirect_response.build_full_redirect_uri(), expected_uri);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Account for unordered query parameters in tests

Since HashMap does not guarantee the order of its entries, the actual query parameters in the URI might not be in the same order as specified. This can cause tests to fail intermittently. Consider parsing the query parameters and asserting their presence regardless of order.

You can adjust the test as follows:

-        assert_eq!(redirect_response.build_full_redirect_uri(), expected_uri);
+        let actual_uri = redirect_response.build_full_redirect_uri();
+        let uri_parts: Vec<&str> = actual_uri.split('?').collect();
+        assert_eq!(uri_parts[0], "/web");
+        let query_params: Vec<&str> = uri_parts[1].split('&').collect();
+        assert!(query_params.contains(&"redirect_url=http://localhost:5080/api/default/short/1234"));
+        assert!(query_params.contains(&"user_id=42"));
📝 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
let expected_uri =
"/web?redirect_url=http://localhost:5080/api/default/short/1234&user_id=42";
assert_eq!(redirect_response.build_full_redirect_uri(), expected_uri);
let expected_uri =
"/web?redirect_url=http://localhost:5080/api/default/short/1234&user_id=42";
let actual_uri = redirect_response.build_full_redirect_uri();
let uri_parts: Vec<&str> = actual_uri.split('?').collect();
assert_eq!(uri_parts[0], "/web");
let query_params: Vec<&str> = uri_parts[1].split('&').collect();
assert!(query_params.contains(&"redirect_url=http://localhost:5080/api/default/short/1234"));
assert!(query_params.contains(&"user_id=42"));

Comment on lines +34 to +45
let mut redirect_uri = self.redirect_relative_uri.clone();

// If there are query parameters, append them to the URI.
if !self.query_params.is_empty() {
let query_string: String = self
.query_params
.iter()
.map(|(key, value)| format!("{}={}", key, value))
.collect::<Vec<String>>()
.join("&");

redirect_uri = format!("{}?{}", redirect_uri, query_string);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle existing query parameters in redirect URI

If redirect_relative_uri already contains query parameters, appending another ? would result in an invalid URL. Consider checking if redirect_relative_uri contains a ? and use the appropriate separator (? or &) when appending the query parameters.

Apply this diff to fix the issue:

             if !self.query_params.is_empty() {
+                let separator = if redirect_uri.contains('?') { '&' } else { '?' };
-                redirect_uri = format!("{}?{}", redirect_uri, query_string);
+                redirect_uri = format!("{}{}{}", redirect_uri, separator, query_string);
             }
📝 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
let mut redirect_uri = self.redirect_relative_uri.clone();
// If there are query parameters, append them to the URI.
if !self.query_params.is_empty() {
let query_string: String = self
.query_params
.iter()
.map(|(key, value)| format!("{}={}", key, value))
.collect::<Vec<String>>()
.join("&");
redirect_uri = format!("{}?{}", redirect_uri, query_string);
let mut redirect_uri = self.redirect_relative_uri.clone();
// If there are query parameters, append them to the URI.
if !self.query_params.is_empty() {
let query_string: String = self
.query_params
.iter()
.map(|(key, value)| format!("{}={}", key, value))
.collect::<Vec<String>>()
.join("&");
let separator = if redirect_uri.contains('?') { '&' } else { '?' };
redirect_uri = format!("{}{}{}", redirect_uri, separator, query_string);
}

Comment on lines +491 to +492
.service(short_url::shorten)
.service(short_url::retrieve),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Reconsider moving short_url::retrieve behind authentication middleware

By adding short_url::retrieve to get_service_routes, which applies authentication middleware, unauthenticated users may not be able to access short URLs. Since one of the PR objectives is to fix issues where users cannot access shared short URLs, especially in incognito mode or when using SSO, moving this route behind authentication might prevent users from retrieving short URLs without logging in. Consider making short_url::retrieve accessible without requiring authentication to ensure that shared links work as intended.

To address this, you can move short_url::retrieve to an unauthenticated route. Here's a suggested change:

-    .service(short_url::shorten)
-    .service(short_url::retrieve),
+    .service(short_url::shorten),

In the get_basic_routes function, add short_url::retrieve without authentication:

 cfg.service(
     web::scope("/auth")
         .wrap(cors.clone())
         .service(users::authentication)
         .service(users::get_presigned_url)
         .service(users::get_auth),
 );
+
+cfg.service(
+    web::scope("/short")
+        .wrap(cors.clone())
+        .service(short_url::retrieve),
+);

Committable suggestion was skipped due to low confidence.

@hengfeiyang hengfeiyang merged commit aac7025 into main Oct 14, 2024
26 checks passed
@hengfeiyang hengfeiyang deleted the short_url_fixes branch October 14, 2024 07:24
@coderabbitai coderabbitai bot mentioned this pull request Dec 13, 2024
3 tasks
@coderabbitai coderabbitai bot mentioned this pull request Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
☢️ Bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Short URL link related Issues/Observations
5 participants