Skip to content

refactor: deduplicate shared utilities into utils module#30

Merged
darkmaster0345 merged 1 commit into
mainfrom
gt/toast/2cad97a6
Jun 19, 2026
Merged

refactor: deduplicate shared utilities into utils module#30
darkmaster0345 merged 1 commit into
mainfrom
gt/toast/2cad97a6

Conversation

@darkmaster0345

@darkmaster0345 darkmaster0345 commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Move constant_time_eq, is_vx2_file, format_size, and HumanBytes from cli.rs and gui.rs into src/utils.rs. Export from lib.rs and update both callers to import from crate::utils.

Summary by Sourcery

Deduplicate shared helper functionality into a reusable utils module and update CLI and GUI to use it.

Enhancements:

  • Extract constant-time equality comparison, VX2 file detection, and size-formatting utilities into a shared utils module.
  • Expose the new utils module from the library for reuse across the crate.
  • Update GUI password comparison to use the byte-slice constant-time equality implementation.

Move constant_time_eq, is_vx2_file, format_size, and HumanBytes
from cli.rs and gui.rs into src/utils.rs. Export from lib.rs and
update both callers to import from crate::utils.
@sourcery-ai

sourcery-ai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors several duplicated helper functions into a new shared utils module and updates cli and gui to consume the shared APIs, unifying constant-time comparison, VX2 file detection, and human-readable size formatting across the crate.

File-Level Changes

Change Details Files
Introduce shared utils module and export it from the crate root.
  • Add new utils module containing constant_time_eq, is_vx2_file, format_size, and HumanBytes implementations
  • Expose utils module publicly from lib.rs so it can be used by both the CLI binary and the GUI
neuron-encrypt/src/utils.rs
neuron-encrypt/src/lib.rs
Deduplicate and centralize constant-time equality logic.
  • Remove local constant_time_eq implementations from cli.rs and gui.rs
  • Standardize on a single byte-slice-based constant_time_eq in utils, adjusting GUI code to call it with password.as_bytes() and confirm_password.as_bytes()
neuron-encrypt/src/bin/cli.rs
neuron-encrypt/src/gui.rs
neuron-encrypt/src/utils.rs
Deduplicate VX2 file detection and size-formatting utilities.
  • Remove local is_vx2_file implementations from cli.rs and gui.rs and use the shared utils::is_vx2_file instead
  • Move GUI-only format_size and CLI-only HumanBytes into utils to be reusable and keep formatting behavior in one place
neuron-encrypt/src/bin/cli.rs
neuron-encrypt/src/gui.rs
neuron-encrypt/src/utils.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@darkmaster0345 darkmaster0345 merged commit 2c37745 into main Jun 19, 2026
2 of 4 checks passed
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@darkmaster0345, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 59 minutes and 11 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 10cd4ba1-c0c0-4c5f-93cb-72eb51110897

📥 Commits

Reviewing files that changed from the base of the PR and between 7cd2972 and 06f892c.

📒 Files selected for processing (4)
  • neuron-encrypt/src/bin/cli.rs
  • neuron-encrypt/src/gui.rs
  • neuron-encrypt/src/lib.rs
  • neuron-encrypt/src/utils.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gt/toast/2cad97a6

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="neuron-encrypt/src/utils.rs" line_range="1-20" />
<code_context>
+pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
+    let len_a = a.len();
+    let len_b = b.len();
+    let max_len = len_a.max(len_b);
+
+    let mut byte_comparison_result = 0;
+
+    for i in 0..max_len {
+        let byte_a = a.get(i).unwrap_or(&0);
+        let byte_b = b.get(i).unwrap_or(&0);
+        byte_comparison_result |= byte_a ^ byte_b;
+    }
+
+    let len_diff = len_a ^ len_b;
+    let len_mismatch_flag = (((len_diff | len_diff.wrapping_neg()) >> (usize::BITS - 1)) & 1) as u8;
+
+    let final_result = byte_comparison_result | len_mismatch_flag;
+
+    final_result == 0
</code_context>
<issue_to_address>
**suggestion:** Consider a more flexible signature for `constant_time_eq` to avoid repeated `as_bytes()` at call sites.

Now that this utility is shared between CLI and GUI, consider making it generic over `AsRef<[u8]>`, e.g. `pub fn constant_time_eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: A, b: B) -> bool`. That would allow direct use with `String`, `&str`, `Vec<u8>`, etc., and remove the need for repeated `as_bytes()` calls while keeping the implementation unchanged.

```suggestion
pub fn constant_time_eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: A, b: B) -> bool {
    let a = a.as_ref();
    let b = b.as_ref();

    let len_a = a.len();
    let len_b = b.len();
    let max_len = len_a.max(len_b);

    let mut byte_comparison_result = 0;

    for i in 0..max_len {
        let byte_a = a.get(i).unwrap_or(&0);
        let byte_b = b.get(i).unwrap_or(&0);
        byte_comparison_result |= byte_a ^ byte_b;
    }

    let len_diff = len_a ^ len_b;
    let len_mismatch_flag = (((len_diff | len_diff.wrapping_neg()) >> (usize::BITS - 1)) & 1) as u8;

    let final_result = byte_comparison_result | len_mismatch_flag;

    final_result == 0
}
```
</issue_to_address>

### Comment 2
<location path="neuron-encrypt/src/gui.rs" line_range="413-414" />
<code_context>
         }

-        if self.mode == Mode::Encrypt && !constant_time_eq(&self.password, &self.confirm_password) {
+        if self.mode == Mode::Encrypt && !constant_time_eq(self.password.as_bytes(), self.confirm_password.as_bytes()) {
             self.status = Some("Passphrases do not match.".to_owned());
             return;
         }
</code_context>
<issue_to_address>
**suggestion:** The repeated `password`/`confirm_password` comparisons could be centralized to reduce duplication and potential drift.

Since this comparison appears in multiple branches with similar conditions, consider extracting a helper like `fn passwords_match(&self) -> bool` that performs the mode check and constant-time comparison. This avoids duplicated logic and keeps any future change to the comparison behavior in a single place.

Suggested implementation:

```rust
        if !self.passwords_match() {
            self.status = Some("Passphrases do not match.".to_owned());
            return;
        }

```

To fully implement the suggestion and centralize the comparison logic, you should:

1. Add a helper method on the relevant GUI/app struct (the one that owns `mode`, `password`, and `confirm_password`) inside its `impl` block, for example:
   ```rust
   impl App {  // or whatever the struct is named
       fn passwords_match(&self) -> bool {
           if self.mode != Mode::Encrypt {
               return true;
           }

           constant_time_eq(self.password.as_bytes(), self.confirm_password.as_bytes())
       }
   }
   ```

2. Replace any other occurrences of repeated comparison logic that look like:
   ```rust
   if self.mode == Mode::Encrypt && !constant_time_eq(self.password.as_bytes(), self.confirm_password.as_bytes()) { ... }
   ```
   or similar direct comparisons, with:
   ```rust
   if !self.passwords_match() { ... }
   ```
   so that all passphrase comparison behavior is centralized in `passwords_match`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +1 to +20
pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
let len_a = a.len();
let len_b = b.len();
let max_len = len_a.max(len_b);

let mut byte_comparison_result = 0;

for i in 0..max_len {
let byte_a = a.get(i).unwrap_or(&0);
let byte_b = b.get(i).unwrap_or(&0);
byte_comparison_result |= byte_a ^ byte_b;
}

let len_diff = len_a ^ len_b;
let len_mismatch_flag = (((len_diff | len_diff.wrapping_neg()) >> (usize::BITS - 1)) & 1) as u8;

let final_result = byte_comparison_result | len_mismatch_flag;

final_result == 0
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider a more flexible signature for constant_time_eq to avoid repeated as_bytes() at call sites.

Now that this utility is shared between CLI and GUI, consider making it generic over AsRef<[u8]>, e.g. pub fn constant_time_eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: A, b: B) -> bool. That would allow direct use with String, &str, Vec<u8>, etc., and remove the need for repeated as_bytes() calls while keeping the implementation unchanged.

Suggested change
pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
let len_a = a.len();
let len_b = b.len();
let max_len = len_a.max(len_b);
let mut byte_comparison_result = 0;
for i in 0..max_len {
let byte_a = a.get(i).unwrap_or(&0);
let byte_b = b.get(i).unwrap_or(&0);
byte_comparison_result |= byte_a ^ byte_b;
}
let len_diff = len_a ^ len_b;
let len_mismatch_flag = (((len_diff | len_diff.wrapping_neg()) >> (usize::BITS - 1)) & 1) as u8;
let final_result = byte_comparison_result | len_mismatch_flag;
final_result == 0
}
pub fn constant_time_eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: A, b: B) -> bool {
let a = a.as_ref();
let b = b.as_ref();
let len_a = a.len();
let len_b = b.len();
let max_len = len_a.max(len_b);
let mut byte_comparison_result = 0;
for i in 0..max_len {
let byte_a = a.get(i).unwrap_or(&0);
let byte_b = b.get(i).unwrap_or(&0);
byte_comparison_result |= byte_a ^ byte_b;
}
let len_diff = len_a ^ len_b;
let len_mismatch_flag = (((len_diff | len_diff.wrapping_neg()) >> (usize::BITS - 1)) & 1) as u8;
let final_result = byte_comparison_result | len_mismatch_flag;
final_result == 0
}

Comment thread neuron-encrypt/src/gui.rs
Comment on lines +413 to 414
if self.mode == Mode::Encrypt && !constant_time_eq(self.password.as_bytes(), self.confirm_password.as_bytes()) {
self.status = Some("Passphrases do not match.".to_owned());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: The repeated password/confirm_password comparisons could be centralized to reduce duplication and potential drift.

Since this comparison appears in multiple branches with similar conditions, consider extracting a helper like fn passwords_match(&self) -> bool that performs the mode check and constant-time comparison. This avoids duplicated logic and keeps any future change to the comparison behavior in a single place.

Suggested implementation:

        if !self.passwords_match() {
            self.status = Some("Passphrases do not match.".to_owned());
            return;
        }

To fully implement the suggestion and centralize the comparison logic, you should:

  1. Add a helper method on the relevant GUI/app struct (the one that owns mode, password, and confirm_password) inside its impl block, for example:

    impl App {  // or whatever the struct is named
        fn passwords_match(&self) -> bool {
            if self.mode != Mode::Encrypt {
                return true;
            }
    
            constant_time_eq(self.password.as_bytes(), self.confirm_password.as_bytes())
        }
    }
  2. Replace any other occurrences of repeated comparison logic that look like:

    if self.mode == Mode::Encrypt && !constant_time_eq(self.password.as_bytes(), self.confirm_password.as_bytes()) { ... }

    or similar direct comparisons, with:

    if !self.passwords_match() { ... }

    so that all passphrase comparison behavior is centralized in passwords_match.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics -2 complexity · 0 duplication

Metric Results
Complexity -2
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

}
}

pub struct HumanBytes(pub u64);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔥 The Roast: You moved two byte-size formatters into the same module and let them keep different GB precision (format_size uses {:.1}, HumanBytes uses {:.2}). That's not deduplication so much as putting twins in matching outfits with different shoe sizes.

🩹 The Fix: Pick one source of truth: either have HumanBytes delegate to format_size(self.0) if one decimal is acceptable, or factor a shared formatter that takes precision and use it from both paths. Add a small boundary-size test/table so future formatting tweaks don't quietly diverge.

📏 Severity: nitpick

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

Code Review Roast 🔥

Verdict: 1 New Issue Found (2 Existing Active Comments) | Recommendation: Address before merge

Overview

Active issue count includes 2 pre-existing Sourcery comments plus 1 new Kilo comment.

Severity Count
🚨 critical 0
⚠️ warning 0
💡 suggestion 2
🤏 nitpick 1
Issue Details (click to expand)
File Line Roast
neuron-encrypt/src/utils.rs 20 Existing: consider a more flexible constant_time_eq signature to avoid repeated as_bytes() call sites.
neuron-encrypt/src/gui.rs 414 Existing: repeated password comparison logic should be centralized to avoid drift.
neuron-encrypt/src/utils.rs 41 New: format_size and HumanBytes now live side by side with different GB precision, inviting formatter drift.

Fix these issues in Kilo Cloud

🏆 Best part: Oh wait, extracting duplicated helpers into a shared module is actually the right instinct; I had my flamethrower warmed up and found a refactor with a spine.

💀 Worst part: The byte-size formatter twins living in the same module with different GB precision is the biggest new concern — tiny, but it smells like future drift wearing a fake mustache.

📊 Overall: Mostly a clean utility extraction; fix the formatter drift and the existing active comments, then this PR can stop looking over its shoulder.

Files Reviewed (4 files)
  • neuron-encrypt/src/utils.rs - 2 issues
  • neuron-encrypt/src/gui.rs - 1 issue
  • neuron-encrypt/src/bin/cli.rs - 0 issues
  • neuron-encrypt/src/lib.rs - 0 issues

Reviewed by nex-n2-pro:free · Input: 829K · Output: 12.9K · Cached: 0

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