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

[breaking] Technical debt #306

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft

[breaking] Technical debt #306

wants to merge 3 commits into from

Conversation

freedit-dev
Copy link
Member

@freedit-dev freedit-dev commented Nov 26, 2024

Summary by CodeRabbit

Release Notes

  • Documentation

    • Updated the README.md to reflect changes in the command for generating local documentation, now including private items.
    • Minor formatting adjustments and clarifications added throughout the document.
  • New Features

    • Enhanced user management functionality with direct retrieval of user attributes from memory, reducing database interactions.
    • Introduced stricter validation rules for inn management, ensuring unique inn names and controlled type transitions.
  • Bug Fixes

    • Simplified logic for handling user public keys and access to private inns, improving clarity and efficiency.
  • Refactor

    • Streamlined data handling and retrieval processes across various controller functions, enhancing code clarity and performance.

Copy link
Contributor

coderabbitai bot commented Nov 26, 2024

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This pull request introduces a series of modifications across multiple files in the freedit project, primarily focusing on the README.md documentation and several controller files. Key changes include updates to the documentation generation command, simplifications in data handling logic, and restructuring of user management functionalities. The changes enhance clarity and streamline processes by reducing unnecessary database interactions and enforcing stricter validation rules.

Changes

File Change Summary
README.md Updated documentation generation command; minor formatting adjustments and clarifications made throughout.
src/controller/admin.rs Removed handling for "inns_private" and "home_pages"; modified logic for "feed_errs" and "pub_keys".
src/controller/inn.rs Refined logic for inn type transitions; ensured unique inn names; updated access control for private inns.
src/controller/message.rs Simplified user public key handling; retrieved user object directly from the database.
src/controller/meta_handler.rs Updated home page retrieval logic; removed nested database access; added several new methods and structs.
src/controller/mod.rs Removed default values in data tables; added new fields to User struct; introduced is_private method.
src/controller/user.rs Simplified home page handling; reduced database interactions for user attributes; updated cookie generation.

Possibly related PRs

  • Garde #259: The changes in src/controller/admin.rs involve modifications to the function signatures and imports, which may relate to the overall structure and documentation updates in the README.md regarding the handling of commands and functionality within the project.

🐇 In the meadow, changes bloom,
A README brightens every room.
With simpler paths and clearer ways,
Our code now dances, sings, and plays.
From inns to users, all refined,
A joyful leap for humankind! 🌼


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.

@freedit-dev
Copy link
Member Author

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Nov 26, 2024

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 3

🧹 Outside diff range and nitpick comments (6)
src/controller/inn.rs (1)

Line range hint 980-985: Simplify Conditional Logic for Better Readability

You can simplify the conditional statements in the inn function by combining conditions to reduce redundancy and enhance clarity.

Apply this diff to simplify the code:

-    if inn.is_private() {
-        if joined_inns.contains(&iid) || is_site_admin {
-            index = get_pids_by_iids(&DB, &[iid], &page_params)?;
-        }
-    } else {
-        index = get_pids_by_iids(&DB, &[iid], &page_params)?;
-    }
+    if !inn.is_private() || joined_inns.contains(&iid) || is_site_admin {
+        index = get_pids_by_iids(&DB, &[iid], &page_params)?;
+    }
README.md (1)

56-56: Consider adding a note about private documentation

It would be helpful to add a note explaining why private items are being documented and who the target audience is for this documentation.

Consider adding this note:

 ```bash
 cargo doc --no-deps --document-private-items --open

+Note: This command generates documentation for both public and private items,
+intended for maintainers and contributors to understand internal implementation details.


</blockquote></details>
<details>
<summary>src/controller/meta_handler.rs (2)</summary><blockquote>

`74-77`: **Improved data access pattern, but consider enhancing error handling**

The new approach using `get_one` and the `User` struct is more maintainable and type-safe. However, consider adding specific error handling for the database query.


Consider this enhancement:

```diff
-        let user: User = get_one(&DB, "users", claim.uid)?;
+        let user: User = get_one(&DB, "users", claim.uid)
+            .map_err(|e| {
+                error!("Failed to fetch user {}: {}", claim.uid, e);
+                AppError::NotFound
+            })?;

Line range hint 93-93: Consider implementing CSS minification

The TODO comment indicates missing CSS minification. This could improve performance by reducing the payload size.

Would you like me to help implement CSS minification using a Rust-based solution? I can suggest using the lightningcss crate or provide a build-time minification script.

src/controller/mod.rs (1)

299-303: Add documentation and consider pattern matching for is_private.

The new method is functionally correct but could be improved for clarity and maintainability.

Consider this alternative implementation:

-    fn is_private(&self) -> bool {
-        InnType::from(self.inn_type) == InnType::Private
-            || InnType::from(self.inn_type) == InnType::PrivateHidden
-    }
+    /// Returns true if the inn has private access restrictions
+    /// (either Private or PrivateHidden type)
+    fn is_private(&self) -> bool {
+        match InnType::from(self.inn_type) {
+            InnType::Private | InnType::PrivateHidden => true,
+            _ => false,
+        }
+    }
src/controller/user.rs (1)

767-772: Consider refactoring language validation

The hardcoded language validation could be improved by:

  1. Moving supported languages to a constant or configuration
  2. Using a proper language code enum or validation system

This would make it easier to maintain and extend supported languages.

+ const SUPPORTED_LANGUAGES: &[&str] = &["en", "zh_cn", "ja", "fr"];
+
  match input.lang.as_str() {
-     "en" | "zh_cn" | "ja" | "fr" => {
+     lang if SUPPORTED_LANGUAGES.contains(&lang) => {
          claim.update_lang(&DB, &input.lang)?;
          user.lang = Some(input.lang.clone());
      }
      _ => {}
  };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 196613b and 8a23439.

📒 Files selected for processing (7)
  • README.md (1 hunks)
  • src/controller/admin.rs (1 hunks)
  • src/controller/inn.rs (1 hunks)
  • src/controller/message.rs (4 hunks)
  • src/controller/meta_handler.rs (2 hunks)
  • src/controller/mod.rs (6 hunks)
  • src/controller/user.rs (4 hunks)
🔇 Additional comments (10)
README.md (1)

56-56: Verify the intention behind documenting private items

The addition of --document-private-items flag will expose documentation for private implementation details. While this can be helpful for maintainers, it might not align with the project's encapsulation strategy.

Let's check if this change is consistent with the project's documentation approach:

✅ Verification successful

Based on the codebase analysis, I can now generate the final response:

Documentation change aligns with project's practices

The addition of --document-private-items flag is consistent with the project's documentation approach, as evidenced by:

  1. The extensive use of private documentation comments (///) throughout the codebase, particularly in src/controller/ modules
  2. The presence of detailed internal API documentation for private functions and implementation details
  3. The project's focus on developer understanding, shown by comprehensive documentation of internal workings

The change helps make this internal documentation accessible through cargo doc, benefiting maintainers and contributors.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check current documentation practices
# Look for any documentation guidelines or discussions about private items

# Check if there are any existing documentation guidelines
fd -g "*CONTRIBUTING*" -g "*DEVELOPMENT*" -g "*DOCS*" -X cat {} 2>/dev/null

# Check for any discussions about documentation in recent commits
git log --grep="doc" --grep="documentation" -i --pretty=format:"%h %s" -n 5

Length of output: 67


Script:

#!/bin/bash
# Let's check the README.md content to understand the documentation context
cat README.md

# Also check for any Rust documentation comments in the codebase
rg "///" -A 2

# Look for any configuration files that might have documentation settings
fd -g "*.toml" -X cat {}

Length of output: 57350

src/controller/message.rs (3)

10-10: LGTM: Import changes align with the new data access pattern.

The addition of set_one import supports the transition to direct user object manipulation, which is a cleaner approach.


38-49: ⚠️ Potential issue

Fix incorrect username in template data

There's a bug in the template data construction. The receiver_name is being set to the sender's username (user.username) instead of the recipient's username (rcpt.username).

Apply this fix:

  let page_message = PageMessage {
      receiver_id: uid,
      page_data: PageData::new(&title, &site_config, Some(claim), false),
      pub_key: rcpt.pub_key,
-     receiver_name: user.username,
+     receiver_name: rcpt.username,
  };

Likely invalid or redundant comment.


133-133: ⚠️ Potential issue

Remove HTML cleaning for public key

Using clean_html on a public key is incorrect as it could alter the key's content. Public keys should be handled as raw data without any sanitization.

Apply this fix:

-   let pub_key = clean_html(&input.pub_key);
+   let pub_key = input.pub_key;

Likely invalid or redundant comment.

src/controller/meta_handler.rs (1)

3-4: LGTM! Import changes align with the new data access pattern

The addition of User and get_one imports, coupled with the removal of u32_to_ivec, indicates a positive shift towards using higher-level database abstractions.

src/controller/admin.rs (1)

Line range hint 263-267: Potential XSS vulnerability in feed error message display

The current implementation displays feed error messages without proper HTML sanitization, which could lead to XSS vulnerabilities if the error messages contain malicious HTML/JavaScript content. This is particularly critical since the admin template has HTML escaping disabled (escape = "none").

Consider applying these improvements:

 "feed_errs" => {
     let id = ivec_to_u32(&k);
     let msg = String::from_utf8_lossy(&v);
-    ones.push(format!("{id}: {msg}"));
+    let sanitized_msg = clean_html(&msg);
+    ones.push(format!("{id}: {sanitized_msg}"));
 }

Additional recommendations:

  1. Consider adding timestamp information for better error tracking
  2. Implement pagination or limit the number of errors shown to prevent potential DoS

Let's verify the potential impact:

src/controller/mod.rs (1)

12-14: Documentation needs clarification for empty value fields.

Several table definitions now show empty value fields in the documentation. This change could impact data migration and backwards compatibility. Please:

  1. Clarify if these fields still store values
  2. Document the expected value format if applicable
  3. Update migration guides if necessary

Affected tables: user_following, user_followers, user_stats, messages, and others.

Consider maintaining a separate schema version documentation to track these changes and help with future migrations.

Also applies to: 17-19, 33-34, 36-36, 54-57, 59-59, 61-61, 68-68, 70-72, 76-76, 83-85, 99-99, 106-107

✅ Verification successful

Let me check the README.md content and search for any database schema related information before making a conclusion.


Let me check the actual database initialization and usage patterns to understand if these empty values are intentional.


Let me check the actual database value insertion patterns for these specific tables.


Based on the evidence gathered, I can now generate the final response:

Documentation accurately reflects empty value fields - they are used as key-only indices

The empty value fields in the documentation are correct and intentional. The code shows that these tables are used as key-only indices where:

  • user_following and user_followers tables store relationships using composite keys (uid#uid) with empty values (&[])
  • user_stats stores counts with timestamp-based keys and numeric values

The implementation consistently uses these tables as documented:

  • Following/follower relationships are tracked by key existence only
  • Stats are tracked with incrementing counters
  • No default values are needed as the presence/absence of keys is sufficient
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any migration scripts or documentation
# that might need updating due to schema changes

# Look for migration files
fd -t f "migration|upgrade" -X echo "Found migration file: {}"

# Check for documentation about database schema
fd -t f "README|SCHEMA|DATABASE" -X echo "Found documentation: {}"

Length of output: 166


Script:

#!/bin/bash
# Check README.md content for database schema information
cat README.md

# Search for any database schema related files or documentation in the codebase
rg -i "schema|database structure|table structure" --type rust

# Look for any database initialization or setup code
ast-grep --pattern 'fn $_($$$ db: $$$) {
  $$$
}'

Length of output: 3559


Script:

#!/bin/bash
# Look for database tree initialization and usage
rg -A 5 "open_tree|Tree::new" --type rust

# Check for any database value insertion patterns
ast-grep --pattern 'insert($$$)'

# Look for database related tests that might show expected values
fd -t f "test" -e rs -X rg -l "user_following|user_followers|user_stats"

Length of output: 56121


Script:

#!/bin/bash
# Search for user_following/followers/stats insertions and their values
rg -B 2 -A 2 "user_following|user_followers|user_stats" --type rust | grep -A 2 "insert"

# Look for any tests or documentation that shows the expected format
ast-grep --pattern 'fn test_$_($$$) {
  $$$
  user_following$$$
  $$$
}'

# Check for any comments or documentation about these tables
rg -i "user_following|user_followers|user_stats" --type rust --type md -C 2

Length of output: 7448

src/controller/user.rs (3)

644-644: LGTM: PageUserSetting struct update

The addition of the home_page field to PageUserSetting is consistent with the refactoring to store user preferences in the User struct.


765-765: LGTM: Home page preference update

The assignment of the home_page preference is properly implemented.


1217-1217: LGTM: Session claim language preference

The addition of the language preference to the session claim is properly implemented and consistent with the refactoring goals.

Comment on lines +133 to +135
let mut user: User = get_one(&DB, "users", claim.uid)?;
user.pub_key = Some(pub_key);
set_one(&DB, "users", claim.uid, &user)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add size limit validation for public key

The code should validate the size of the public key to prevent potential DoS attacks through extremely large keys or database storage issues.

Consider adding a size limit check:

    let mut user: User = get_one(&DB, "users", claim.uid)?;
+   if input.pub_key.len() > 2048 {  // Adjust size limit as needed
+       return Err(AppError::InvalidInput("Public key too large".into()));
+   }
    user.pub_key = Some(pub_key);
    set_one(&DB, "users", claim.uid, &user)?;

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +106 to +107
let user: User = get_one(&DB, "users", claim.uid)?;
let pub_key = user.pub_key.unwrap_or_default();
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Public key validation is handled through HTML sanitization only

Based on the code analysis, the public key is only sanitized using clean_html() before storage, without any cryptographic validation. While this prevents XSS attacks, it doesn't ensure the key meets cryptographic standards.

  • The key is stored in User.pub_key as an optional String
  • In key_post(), the key is only processed through clean_html(&input.pub_key)
  • No cryptographic validation is performed despite the codebase having crypto capabilities (as seen in src/lib.rs and src/controller/user.rs)
🔗 Analysis chain

Verify public key format validation

While the code handles the absence of a public key gracefully, there's no validation of the public key format. Consider adding validation to ensure the key meets the required format and security standards.

Let's check if there's any key validation elsewhere in the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for public key validation patterns
rg -A 5 'pub_key.*valid|validate.*pub_key|check.*pub_key'

# Search for any crypto-related validation functions
ast-grep --pattern 'fn $_(pub_key: $_) {
  $$$
}'

Length of output: 111


Script:

#!/bin/bash
# Let's search for public key related code more broadly
rg -A 5 "pub_key"

# Also search for any key validation or verification functions
rg -A 5 "verify.*key|validate.*key|check.*key"

# Look for crypto-related imports that might handle key validation
rg "use.*crypto"

Length of output: 134574


Script:

#!/bin/bash
# Let's search for key-related functionality and validation
rg -A 5 "pub_key|public.*key" src/

# Look for any crypto-related code or key handling
rg -A 5 "crypto|key.*valid|verify" src/

# Check for any key-related functions in message handling
ast-grep --pattern 'fn $_(pub_key: $_) {
  $$$
}' src/controller/message.rs

Length of output: 3835

Comment on lines +160 to +162
lang: Option<String>,
home_page: u8,
pub_key: Option<String>,
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Document and validate new User fields.

The new fields need documentation and validation:

  1. lang: Consider validating against supported languages in I18N
  2. home_page: Document valid values and add validation

Add validation and documentation:

 #[derive(Default, Encode, Decode, Serialize, Debug)]
 struct User {
     uid: u32,
     username: String,
     password_hash: String,
     recovery_hash: Option<String>,
     created_at: i64,
     role: u8,
     url: String,
     about: String,
+    /// User's preferred language code (e.g., "en", "zh_cn")
+    #[garde(custom(supported_language))]
     lang: Option<String>,
+    /// User's preferred home page view
+    /// Values:
+    /// - 0: Default view
+    /// - 1: Timeline view
+    /// - 2: Custom view
+    #[garde(range(max = 2))]
     home_page: u8,
     pub_key: Option<String>,
 }

+impl User {
+    fn supported_language(lang: &Option<String>) -> garde::Result {
+        if let Some(lang) = lang {
+            if !["en", "zh_cn", "ja", "fr"].contains(&lang.as_str()) {
+                return Err(garde::Error::new("unsupported language"));
+            }
+        }
+        Ok(())
+    }
+}
📝 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
lang: Option<String>,
home_page: u8,
pub_key: Option<String>,
#[derive(Default, Encode, Decode, Serialize, Debug)]
struct User {
uid: u32,
username: String,
password_hash: String,
recovery_hash: Option<String>,
created_at: i64,
role: u8,
url: String,
about: String,
/// User's preferred language code (e.g., "en", "zh_cn")
#[garde(custom(supported_language))]
lang: Option<String>,
/// User's preferred home page view
/// Values:
/// - 0: Default view
/// - 1: Timeline view
/// - 2: Custom view
#[garde(range(max = 2))]
home_page: u8,
pub_key: Option<String>,
}
impl User {
fn supported_language(lang: &Option<String>) -> garde::Result {
if let Some(lang) = lang {
if !["en", "zh_cn", "ja", "fr"].contains(&lang.as_str()) {
return Err(garde::Error::new("unsupported language"));
}
}
Ok(())
}
}

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

Successfully merging this pull request may close these issues.

1 participant