Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions src/context/AuthContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import axios from "axios";
import { auth, db, signInWithGitHub, signOutUser } from "../lib/firebase";
import { validateUserData } from "../utils/inputValidation";
import logger from "../utils/logger";
import {
userDataCache,
listenerOptimizer,
Expand Down Expand Up @@ -97,7 +98,7 @@ const checkAndUpdateStreak = async (data, docRef) => {
});
});
} catch (err) {
console.error("Failed to update streak atomically:", err);
logger.error("Failed to update streak atomically:", err);
}
};

Expand All @@ -110,7 +111,7 @@ export const AuthProvider = ({ children }) => {

useEffect(() => {
if (!auth) {
console.warn("Firebase auth is not initialized; auth listener skipped.");
logger.warn("Firebase auth is not initialized; auth listener skipped.");
return undefined;
}

Expand Down Expand Up @@ -179,7 +180,7 @@ export const AuthProvider = ({ children }) => {
}
})
.catch((error) => {
console.error("Redirect sign-in resolution failure:", error);
logger.error("Redirect sign-in resolution failure:", error);
});

const unsubscribeAuth = onAuthStateChanged(auth, async (currentUser) => {
Expand Down Expand Up @@ -288,7 +289,7 @@ export const AuthProvider = ({ children }) => {

const validation = validateUserData(rawUserData);
if (!validation.isValid) {
console.warn("User data validation warnings:", validation.errors);
logger.warn("User data validation warnings:", validation.errors);
}

const sanitizedUserData = validation.sanitized;
Expand Down Expand Up @@ -345,7 +346,7 @@ export const AuthProvider = ({ children }) => {

return authUser;
} catch (error) {
console.error("Login service failure:", error);
logger.error("Login service failure:", error);
setLoading(false);
throw error;
}
Expand All @@ -363,7 +364,7 @@ export const AuthProvider = ({ children }) => {
setIsOnboarding(false);
setGhAccessToken(null);
} catch (error) {
console.error("Logout failure:", error);
logger.error("Logout failure:", error);
} finally {
setLoading(false);
}
Expand Down Expand Up @@ -398,7 +399,7 @@ export const AuthProvider = ({ children }) => {
inventory: [...(prev.inventory || ["oliver"]), mascotId],
}));
} catch (err) {
console.error("Failed to purchase mascot:", err);
logger.error("Failed to purchase mascot:", err);
throw err;
}
};
Expand All @@ -416,7 +417,7 @@ export const AuthProvider = ({ children }) => {
updatedAt: new Date().toISOString(),
});
} catch (err) {
console.error("Failed to equip mascot:", err);
logger.error("Failed to equip mascot:", err);
throw err;
}
};
Expand Down Expand Up @@ -481,7 +482,7 @@ export const AuthProvider = ({ children }) => {
if (sortedLangs.length > 0) primaryLanguage = sortedLangs[0];
}
} catch (err) {
console.warn("Stars/Language retrieval warning, defaulting:", err);
logger.warn("Stars/Language retrieval warning, defaulting:", err);
}

let commits = 0;
Expand All @@ -493,10 +494,10 @@ export const AuthProvider = ({ children }) => {
{ headers },
),
);
if (commitsRateLimit) console.warn(commitsRateLimit);
if (commitsRateLimit) logger.warn(commitsRateLimit);
else commits = commitsData?.total_count || 0;
} catch (err) {
console.warn("Commits retrieval failed:", err);
logger.warn("Commits retrieval failed:", err);
}

let prs = 0;
Expand All @@ -508,10 +509,10 @@ export const AuthProvider = ({ children }) => {
{ headers },
),
);
if (prsRateLimit) console.warn(prsRateLimit);
if (prsRateLimit) logger.warn(prsRateLimit);
else prs = prsData?.total_count || 0;
} catch (err) {
console.warn("PRs retrieval failed:", err);
logger.warn("PRs retrieval failed:", err);
}

let reviews = 0;
Expand All @@ -523,10 +524,10 @@ export const AuthProvider = ({ children }) => {
{ headers },
),
);
if (reviewsRateLimit) console.warn(reviewsRateLimit);
if (reviewsRateLimit) logger.warn(reviewsRateLimit);
else reviews = reviewsData?.total_count || 0;
} catch (err) {
console.warn("Reviews retrieval failed:", err);
logger.warn("Reviews retrieval failed:", err);
}

let githubStreak = 0;
Expand Down Expand Up @@ -568,7 +569,7 @@ export const AuthProvider = ({ children }) => {
}
}
} catch (err) {
console.warn("GitHub events retrieval failed for streak:", err);
logger.warn("GitHub events retrieval failed for streak:", err);
}

const gitRankPoints =
Expand All @@ -588,10 +589,10 @@ export const AuthProvider = ({ children }) => {
} catch (error) {
const rateLimitMsg = getRateLimitMessage(error);
if (rateLimitMsg) {
console.warn("Rate limit hit:", rateLimitMsg);
logger.warn("Rate limit hit:", rateLimitMsg);
throw new Error(rateLimitMsg, { cause: error });
}
console.error("Error executing GitHub stats fetcher snapshot:", error);
logger.error("Error executing GitHub stats fetcher snapshot:", error);
return {
commits: 0,
prs: 0,
Expand Down Expand Up @@ -660,10 +661,10 @@ export const AuthProvider = ({ children }) => {
} catch (error) {
const rateLimitMsg = getRateLimitMessage(error);
if (rateLimitMsg) {
console.warn("Sync blocked by rate limit:", rateLimitMsg);
logger.warn("Sync blocked by rate limit:", rateLimitMsg);
throw new Error(rateLimitMsg, { cause: error });
}
console.error("Background GitHub sync failed:", error);
logger.error("Background GitHub sync failed:", error);
}
};

Expand Down
13 changes: 7 additions & 6 deletions src/lib/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
persistentMultipleTabManager,
} from "firebase/firestore";
import { getStorage } from "firebase/storage";
import logger from "../utils/logger";

const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
Expand All @@ -40,7 +41,7 @@ const hasRequiredConfig = requiredConfigKeys.every((key) =>
);

if (!hasRequiredConfig) {
console.warn(
logger.warn(
"Firebase is not configured. Auth, database, analytics, and storage services are disabled for this environment.",
);
}
Expand Down Expand Up @@ -100,7 +101,7 @@ if (app && typeof window !== "undefined") {
try {
analyticsInstance = getAnalytics(app);
} catch (error) {
console.warn("Analytics initialization skipped:", error);
logger.warn("Analytics initialization skipped:", error);
}
}

Expand Down Expand Up @@ -142,7 +143,7 @@ export const signInWithGitHub = async (requestRepoScope = false) => {

return { user, accessToken, userData, result };
} catch (error) {
console.error("GitHub sign-in error:", error);
logger.error("GitHub sign-in error:", error);
throw error;
}
};
Expand All @@ -157,7 +158,7 @@ export const signOutUser = async () => {
await signOut(auth);
return true;
} catch (error) {
console.error("Sign out error:", error);
logger.error("Sign out error:", error);
throw error;
}
};
Expand All @@ -174,7 +175,7 @@ export const getCurrentUserToken = async () => {
const token = await user.getIdToken();
return token;
} catch (error) {
console.error("Error getting user token:", error);
logger.error("Error getting user token:", error);
return null;
}
}
Expand All @@ -193,7 +194,7 @@ export const refreshUserToken = async () => {
const token = await user.getIdToken(true);
return token;
} catch (error) {
console.error("Error refreshing user token:", error);
logger.error("Error refreshing user token:", error);
return null;
}
}
Expand Down
59 changes: 59 additions & 0 deletions src/utils/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const logger = {
info: (message, data = {}) => {
if (import.meta.env.DEV) {
console.info(`[INFO] ${message}`, sanitizeData(data));
}
},

error: (message, error, context = {}) => {
if (import.meta.env.DEV) {
console.error(`[ERROR] ${message}`, error, sanitizeData(context));
}
},

warn: (message, data = {}) => {
if (import.meta.env.DEV) {
console.warn(`[WARN] ${message}`, sanitizeData(data));
}
},

debug: (message, data = {}) => {
if (import.meta.env.DEV) {
console.debug(`[DEBUG] ${message}`, sanitizeData(data));
}
},
};

const sanitizeData = (data) => {
if (!data || typeof data !== 'object') {
return data;
}

const sensitiveKeys = [
'userId',
'uid',
'email',
'password',
'token',
'accessToken',
'refreshToken',
'sessionId',
'personalInfo',
'username',
'githubUsername',
'apiKey',
'secret',
];

const sanitized = { ...data };

sensitiveKeys.forEach((key) => {
if (key in sanitized) {
sanitized[key] = '[REDACTED]';
}
});

return sanitized;
};

export default logger;
Loading