Skip to content

Hash password on update#54

Open
numbpill3d wants to merge 1 commit intomainfrom
codex/hash-password-in-findbyidandupdate-or-save
Open

Hash password on update#54
numbpill3d wants to merge 1 commit intomainfrom
codex/hash-password-in-findbyidandupdate-or-save

Conversation

@numbpill3d
Copy link
Collaborator

@numbpill3d numbpill3d commented Jun 8, 2025

Summary

  • ensure password hashing in findByIdAndUpdate and save
  • inject dummy Supabase config in tests
  • mock Item model path in index route tests
  • add tests for password hashing logic

Testing

  • npm test (fails: fetch failed due to missing Supabase credentials)

https://chatgpt.com/codex/tasks/task_e_68450e3887f4832fbb35c49f86c2aac9

Summary by Sourcery

Ensure that user passwords are securely hashed before being stored or updated in the database and bolster test coverage around this logic.

New Features:

  • Hash passwords in User.findByIdAndUpdate
  • Hash passwords in User.save

Tests:

  • Inject dummy Supabase environment variables in route and transaction tests
  • Mock Item model as a virtual module in index route tests
  • Add unit tests to verify password hashing in findByIdAndUpdate and save

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jun 8, 2025

Reviewer's Guide

This PR integrates bcrypt-based password hashing into the User model’s update and save workflows, updates the test suite to inject dummy Supabase configuration and refine mocks, and adds targeted unit tests to verify the new hashing logic.

Sequence Diagram: Password Hashing in User.findByIdAndUpdate

sequenceDiagram
    participant Caller
    participant User_Class as "User (class)"
    participant bcrypt

    Caller->>+User_Class: findByIdAndUpdate(id, updateData)
    alt "updateData.password is present"
        User_Class->>+bcrypt: genSalt(10)
        bcrypt-->>-User_Class: salt
        User_Class->>+bcrypt: hash(updateData.password, salt)
        bcrypt-->>-User_Class: hashedPassword
        User_Class->>User_Class: updateData.password = hashedPassword
    end
    User_Class->>User_Class: (proceeds with database update)
    User_Class-->>-Caller: User object or null
Loading

Sequence Diagram: Password Hashing in User.save

sequenceDiagram
    participant Caller
    participant User_Instance as "User (instance)"
    participant bcrypt

    Caller->>+User_Instance: save()
    alt "this.password is present"
        User_Instance->>+bcrypt: genSalt(10)
        bcrypt-->>-User_Instance: salt
        User_Instance->>+bcrypt: hash(this.password, salt)
        bcrypt-->>-User_Instance: hashedPassword
        User_Instance->>User_Instance: this.password = hashedPassword
    end
    User_Instance->>User_Instance: (proceeds with database save)
    User_Instance-->>-Caller: void
Loading

Class Diagram: User Model Method Updates

classDiagram
    class User {
        +async findByIdAndUpdate(id, updateData)
        +async save()
    }
Loading

File-Level Changes

Change Details Files
Implement conditional password hashing in User model methods
  • Check for a password field in findByIdAndUpdate and generate salt/hash before update
  • Apply the same salt/hash workflow in the instance save method prior to persisting
server/models/User.js
Enhance test environment setup with dummy Supabase config and refined mocks
  • Inject SUPABASE_URL, SUPABASE_KEY, and SUPABASE_SERVICE_KEY in route and transaction tests
  • Add { virtual: true } flag to the User and Item model mocks in index route tests
tests/server/routes/index.test.js
tests/wir-transactions.test.js
Add unit tests for password hashing logic in User model
  • Mock database handlers to isolate hashing behavior
  • Spy on bcrypt.genSalt and bcrypt.hash in findByIdAndUpdate and validate update calls
  • Repeat hashing verification in a save() scenario and assert supabaseAdmin.update usage
tests/server/models/user-password.test.js

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

Comment on lines 249 to 250
const userData = {
username: this.username,
Copy link
Contributor

Choose a reason for hiding this comment

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

The method save does not show the conversion of user data keys from camelCase to snake_case before updating the database. If the database schema expects snake_case (as seen in other parts of the code), this inconsistency can lead to bugs or data not being saved correctly. Ensure that data keys are consistently formatted before any database operations to prevent potential issues.

Comment on lines +41 to +42
expect(supabaseAdmin.update).toHaveBeenCalledWith(expect.objectContaining({ password: 'hashed_pw2' }));
});
Copy link
Contributor

Choose a reason for hiding this comment

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

The test uses expect.objectContaining to check if the password field in the object passed to supabaseAdmin.update contains the expected hashed password. While this is useful for partial matching, it might be beneficial to assert the entire object structure to ensure that no unexpected fields are being updated or that all necessary fields are included in the update. This would enhance the robustness of the test by verifying the complete payload.

Recommended Solution:
Consider using a more specific assertion to check the entire object structure, especially if the structure is known and critical. For example:

expect(supabaseAdmin.update).toHaveBeenCalledWith({ id: 'user2', password: 'hashed_pw2' });

Comment on lines +7 to +9
process.env.SUPABASE_URL = process.env.SUPABASE_URL || 'http://localhost';
process.env.SUPABASE_KEY = process.env.SUPABASE_KEY || 'key';
process.env.SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY || 'service';
Copy link
Contributor

Choose a reason for hiding this comment

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

Security Issue: Hardcoded Sensitive Keys

The environment variables for Supabase (SUPABASE_URL, SUPABASE_KEY, SUPABASE_SERVICE_KEY) are being set with hardcoded fallback values directly in the test file. This practice can lead to security risks if sensitive keys are exposed in the codebase.

Recommendation:

  • Use a secure method to manage environment variables, such as loading them from a .env file or a secure vault, especially for sensitive keys. Ensure that no sensitive information is hardcoded in the codebase.

Comment on lines +6 to +8
process.env.SUPABASE_URL = process.env.SUPABASE_URL || 'http://localhost';
process.env.SUPABASE_KEY = process.env.SUPABASE_KEY || 'key';
process.env.SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY || 'service';
Copy link
Contributor

Choose a reason for hiding this comment

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

Hardcoding default values for sensitive keys (SUPABASE_KEY, SUPABASE_SERVICE_KEY) directly in the test file poses a security risk. It's recommended to manage these keys securely, for example, by using environment-specific configuration files or secret management tools that do not expose these keys in the codebase. This approach helps prevent accidental exposure and misuse of sensitive keys.

Comment on lines +6 to +8
process.env.SUPABASE_URL = process.env.SUPABASE_URL || 'http://localhost';
process.env.SUPABASE_KEY = process.env.SUPABASE_KEY || 'key';
process.env.SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY || 'service';
Copy link
Contributor

Choose a reason for hiding this comment

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

Direct manipulation of environment variables within the test file (SUPABASE_URL, SUPABASE_KEY, SUPABASE_SERVICE_KEY) can lead to difficulties in managing changes in the environment configuration. Consider using a centralized configuration management approach, such as a dedicated configuration module or file that handles all environment settings. This would improve the maintainability and scalability of the test environment setup.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @numbpill3d - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

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.

*/
async save() {
try {
if (this.password) {
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Hashing all passwords on save may cause double-hashing

Currently, the save method re-hashes the password every time, even if it hasn't changed. This can result in double-hashing and lock users out. Only hash the password if it was modified.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant