Implement combined URL auth key and password authentication for enhanced security#31
Implement combined URL auth key and password authentication for enhanced security#31
Conversation
…ystem Co-authored-by: emilkrebs <68400102+emilkrebs@users.noreply.github.com>
Co-authored-by: emilkrebs <68400102+emilkrebs@users.noreply.github.com>
…alidation Co-authored-by: emilkrebs <68400102+emilkrebs@users.noreply.github.com>
lib/validation/note.ts
Outdated
| ), | ||
| iv: v.pipe( | ||
| v.string(), | ||
| v.nonEmpty('IV is required for encryption'), |
There was a problem hiding this comment.
@copilot The IV is not used for form validation, only for server validation.
There was a problem hiding this comment.
@copilot remove IV from this schema and only validate on the server instead
There was a problem hiding this comment.
Agreed! I've removed the iv field from the form validation schema and created a separate createNoteServerSchema for server-side validation only. The client form now only validates user inputs. Commit: 473d2d1
There was a problem hiding this comment.
Done! I've removed the IV field from the createNoteServerSchema and now validate the IV directly in the server code instead of through valibot schema validation. Since IV is system-generated data (not user input), direct validation is more appropriate than schema validation. Commit: a2d50b5
| v.maxLength(NOTE_PASSWORD_MAX_LENGTH, 'Password is too long (max 256 characters)'), | ||
| ), | ||
| ), // Optional password with max length | ||
| authKey: v.optional( |
There was a problem hiding this comment.
@copilot The authKey is not used for form validation, only for server validation.
There was a problem hiding this comment.
@copilot remove authKey from this schema and only validate on the server instead
There was a problem hiding this comment.
Done! I've removed authKey from the form validation schema (createNoteSchema) and created a separate createNoteServerSchema that includes both iv and authKey fields for server-side validation only. The client form validation now only handles user input fields. Commit: 473d2d1
There was a problem hiding this comment.
Pull Request Overview
This PR implements a dual-layer authentication system combining URL auth keys with optional passwords for enhanced security. The system always generates auth keys and allows optional password protection for maximum flexibility.
- Always generates auth keys regardless of password presence for URL-based access
- Combines auth key and password for encryption when both are provided
- Maintains backward compatibility with existing password-only and auth-key-only notes
Reviewed Changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/main_test.ts | Updated API tests to include auth key authentication flow |
| tests/crypto-service_test.ts | Added comprehensive tests for combined authentication logic |
| routes/api/notes/[id].ts | Enhanced authentication logic to handle dual-layer auth validation |
| routes/api/notes.ts | Modified to accept and store both password and auth key hashes |
| lib/validation/note.ts | Added validation for optional auth key field |
| lib/types.ts | Added authKey field to Note interface |
| lib/services/storage/storage-provider.ts | Updated interface signatures to accept both auth key and password |
| lib/services/storage/remote-storage.ts | Implemented dual authentication for API calls |
| lib/services/note-service.ts | Updated method signatures for combined authentication |
| lib/services/crypto-service.ts | Core implementation of combined key generation and decryption logic |
| islands/ViewNote.tsx | Enhanced UI to handle combined authentication flow |
| IMPLEMENTATION_SUMMARY.md | Added documentation of implementation changes |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // Check authentication - need either password+authKey combo or just authKey (for legacy notes) | ||
| let isAuthenticated = false; | ||
|
|
||
| if (note.password && note.authKey) { | ||
| // Note requires both password and auth key | ||
| if (passwordHash && authKeyHash) { | ||
| isAuthenticated = compareHash(passwordHash, note.password) && compareHash(authKeyHash, note.authKey); | ||
| } | ||
| } else if (note.authKey && !note.password) { | ||
| // Note only requires auth key (legacy or no-password notes) | ||
| if (authKeyHash) { | ||
| isAuthenticated = compareHash(authKeyHash, note.authKey); | ||
| } | ||
| } else if (note.password && !note.authKey) { | ||
| // Legacy note with only password (shouldn't happen with new system but handle gracefully) | ||
| if (passwordHash) { | ||
| isAuthenticated = compareHash(passwordHash, note.password); | ||
| } | ||
| } |
Copilot
AI
Sep 12, 2025
•
There was a problem hiding this comment.
@copilot The authentication logic is duplicated between the POST and DELETE handlers. Extract this into a separate function like authenticateUser(note, passwordHash, authKeyHash) to reduce code duplication and improve maintainability.
| if (note.password && note.authKey) { | ||
| // Note requires both password and auth key | ||
| if (passwordHash && authKeyHash) { | ||
| isAuthenticated = compareHash(passwordHash, note.password) && compareHash(authKeyHash, note.authKey); | ||
| } | ||
| } else if (note.authKey && !note.password) { | ||
| // Note only requires auth key (legacy or no-password notes) | ||
| if (authKeyHash) { | ||
| isAuthenticated = compareHash(authKeyHash, note.authKey); | ||
| } | ||
| } else if (note.password && !note.authKey) { | ||
| // Legacy note with only password (shouldn't happen with new system but handle gracefully) | ||
| if (passwordHash) { | ||
| isAuthenticated = compareHash(passwordHash, note.password); | ||
| } | ||
| } |
Copilot
AI
Sep 12, 2025
•
There was a problem hiding this comment.
@copilot The authentication logic is duplicated between the POST and DELETE handlers. Extract this into a separate function like authenticateUser(note, passwordHash, authKeyHash) to reduce code duplication and improve maintainability.
| </div> | ||
| <p class='text-yellow-300 text-sm font-medium'> | ||
| This note is encrypted and requires a password | ||
| This note is password protected and requires both the URL auth key and password |
There was a problem hiding this comment.
This message assumes the note requires both auth key and password, but it could be shown for auth-key-only notes as well. The message should be more generic or conditionally displayed based on the actual authentication requirements.
There was a problem hiding this comment.
@copilot, hence every URL now should contain a URL fragment, and remove the double confirmation if the note is password-protected. Also shows an appropriate error when the note doesn't have a URL fragment. Make the ViewNote handling more organized
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: emilkrebs <68400102+emilkrebs@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Co-authored-by: emilkrebs <68400102+emilkrebs@users.noreply.github.com>
Co-authored-by: emilkrebs <68400102+emilkrebs@users.noreply.github.com>
Done! I've removed the double confirmation for password-protected notes. Now when a note requires a password, users go directly to the password entry form without seeing an initial "View and Destroy" confirmation dialog first. How it works now:
The change detects when a password is required during the initial decryption attempt and bypasses the confirmation dialog, making the experience much smoother for password-protected notes. Commit: c5b92af |
ivandauthKeyfrom client-side form validation (createNoteSchema) and created separate server-side validation schema (createNoteServerSchema) for server-side validation onlycreateNoteServerSchemaand handle IV validation directly in server code since IV is system-generated data, not user inputKey Changes Made
createNoteSchema): Only validates user input fields (content, password, expiresIn, manualDeletion)createNoteServerSchema): Validates user input fields and server-generatedauthKey(IV now validated directly)createNoteServerSchemafor remaining fieldsThis addresses all feedback regarding validation schemas and user experience improvements for password-protected notes.
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.