[fix] Security update#5
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request introduces a comprehensive security and reliability update to the Feedly extension's content script. It establishes a structured error handling system, improves token caching with TTL and integrity checks, and adds message validation to prevent malicious requests.
Changes:
- Introduced structured error handling with
FeedlyErrorclass, error codes, and user-friendly messages for consistent error reporting across API and DOM operations - Enhanced token caching with TTL expiration and localStorage integrity verification using hash-based change detection
- Added sender validation and settings sanitization to the message listener to prevent spoofed requests and malformed input
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function classifyHttpError(status) { | ||
| if (status === 401 || status === 403) return ErrorCode.AUTH_FAILED; | ||
| if (status === 429) return ErrorCode.RATE_LIMITED; | ||
| if (status >= 500) return ErrorCode.SERVER_ERROR; | ||
| return ErrorCode.UNKNOWN; |
There was a problem hiding this comment.
The classifyHttpError function does not handle 4xx client errors other than 401, 403, and 429. For example, a 400 Bad Request or 404 Not Found would be classified as ErrorCode.UNKNOWN, which has the generic message "Something went wrong. Please try again." Consider adding a case for other 4xx errors (e.g., if (status >= 400 && status < 500) return ErrorCode.CLIENT_ERROR) with a more specific user message like "Invalid request. Please try again or contact support."
| if (simpleHash(currentSessionData) !== tokenCache.sourceHash) { | ||
| return false; |
There was a problem hiding this comment.
The hash-based change detection in isTokenCacheValid could produce false positives (cache invalidation when data hasn't changed) due to hash collisions. While the djb2 algorithm is generally good, collisions are still possible. A more robust approach would be to store the actual token value in the cache and compare it directly with the parsed token from localStorage, or use a more collision-resistant comparison method. This is particularly important for security-sensitive token validation.
| ); | ||
| } | ||
|
|
||
| // DELETE requests may return empty body |
There was a problem hiding this comment.
The response.json() call at line 257 is not wrapped in error handling. If the response body is not valid JSON, this will throw an error that is not a FeedlyError, breaking the consistent error handling pattern. Consider wrapping this in a try-catch block and throwing a FeedlyError with an appropriate error code (e.g., ErrorCode.SERVER_ERROR) if JSON parsing fails.
- Fix djb2 hash: change no-op `hash & hash` to `hash | 0` for proper 32-bit conversion - Implement reload setting: respect `settings.reload` instead of always reloading - Add JSON parse error handling: wrap response.json() in try/catch with FeedlyError - Remove redundant token check: getUserId() already triggers token validation via feedlyApiRequest()
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 9 comments.
Comments suppressed due to low confidence (1)
content.js:207
- There's a potential race condition in getAccessToken when multiple API requests are made concurrently. If two requests call getAccessToken simultaneously when the cache is invalid:
- Both check isTokenCacheValid() and it returns false
- Both call clearAccessTokenCache()
- Both read from localStorage and parse the session
- Both set tokenCache with potentially the same values (harmless) OR different timestamps
While this won't cause data corruption (JavaScript is single-threaded), it results in unnecessary duplicate localStorage reads and JSON parsing. Consider adding a simple lock mechanism or memoization pattern:
let tokenPromise = null;
async function getAccessToken() {
if (isTokenCacheValid()) {
return tokenCache.token;
}
if (tokenPromise) {
return tokenPromise;
}
tokenPromise = (async () => {
// ... existing logic ...
})();
try {
return await tokenPromise;
} finally {
tokenPromise = null;
}
}This is a minor optimization issue but worth considering if the extension frequently makes concurrent API calls.
async function getAccessToken() {
// Return cached token if still valid
if (isTokenCacheValid()) {
return tokenCache.token;
}
// Clear expired/invalid cache
clearAccessTokenCache();
try {
const sessionData = localStorage.getItem("feedly.session");
if (sessionData) {
const session = JSON.parse(sessionData);
if (session.feedlyToken) {
tokenCache = {
token: session.feedlyToken,
cachedAt: Date.now(),
sourceHash: simpleHash(sessionData)
};
return tokenCache.token;
}
}
} catch (e) {
console.warn("[Feedly Opener] Failed to get token from localStorage:", e);
}
return null;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add CLIENT_ERROR to ErrorCode for 4xx HTTP errors - Improve AUTH_FAILED message clarity - Use FeedlyError in getUserId() for consistency - Clarify validateSettings count validation with Number.isFinite - Prioritize WRONG_PAGE error in handleOpen for better UX - Remove unused errorCode field from error response - Add defense-in-depth comment to validateSender - Add defensive catch comment in message listener - Explicitly send reload setting from popup.js
Merge Overview
This pull request introduces significant improvements to error handling, token management, and message security in the
content.jsscript for the Feedly extension. The changes enhance reliability, user feedback, and robustness, particularly around API failures, authentication, and communication between extension components.Error Handling Enhancements:
FeedlyErrorclass, error codes (ErrorCode), and user-friendly messages (UserMessages) for consistent error reporting and debugging. API and DOM errors now use these for more informative feedback.feedlyApiRequest,handleOpenViaAPI,handleOpenViaDOM,handleOpen) to throw and handleFeedlyErrorinstances, providing clearer error propagation and user messages. [1] [2] [3] [4]Token Management Improvements:
tokenCache) that includes TTL expiration and localStorage integrity checks using a hash function, reducing stale token issues. [1] [2]Message Security and Validation:
General Reliability:
handleOpento ensure user-facing error messages are clear and actionable when both API and DOM approaches fail.