Skip to content

fix: prevent unauthorized account.get() call on app init (#746)#785

Open
Arunodoy18 wants to merge 2 commits intoAOSSIE-Org:masterfrom
Arunodoy18:fix/746-guard-account-get
Open

fix: prevent unauthorized account.get() call on app init (#746)#785
Arunodoy18 wants to merge 2 commits intoAOSSIE-Org:masterfrom
Arunodoy18:fix/746-guard-account-get

Conversation

@Arunodoy18
Copy link

@Arunodoy18 Arunodoy18 commented Mar 3, 2026

Summary

Prevents account.get() from being called when no valid session exists.

Changes

  • Added login/session guard before calling setUserProfileData()
  • Prevents 401 errors for guest users
  • No impact on authenticated user flow

Fixes #746

Summary by CodeRabbit

Release Notes

  • New Features

    • Added owner/view mode for profiles, providing distinct UI experiences when viewing your own profile versus others'.
  • Bug Fixes

    • Optimized profile data loading to prevent unnecessary data fetches for guest users.
  • Tests

    • Added test coverage for guest user authentication scenarios.

- Introduce isOwner boolean flag for clear semantic separation
- Hide owner-only UI elements in public view:
  * Edit Profile button
  * Settings access button
  * Email verification prompts
  * AppBar notifications and friends icons
  * Email verification badge
- Replace all widget.isCreatorProfile checks with isOwner flag
- Maintain consistent UI structure without screen duplication
- Preserve all navigation logic and business logic
- Improve code readability with semantic naming

Resolves AOSSIE-Org#749
Only call setUserProfileData() when a valid session exists.
Uses getLoginState to check authentication before fetching profile,
preventing unauthorized account.get() calls for unauthenticated users.

Fixes AOSSIE-Org#746
Copilot AI review requested due to automatic review settings March 3, 2026 05:44
@Arunodoy18 Arunodoy18 requested a review from M4dhav as a code owner March 3, 2026 05:44
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🎉 Welcome @Arunodoy18!
Thank you for your pull request! Our team will review it soon. 🔍

  • Please ensure your PR follows the contribution guidelines. ✅
  • All automated tests should pass before merging. 🔄
  • If this PR fixes an issue, link it in the description. 🔗

We appreciate your contribution! 🚀

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

AuthStateController.onInit() now guards setUserProfileData() calls with a login-state check to prevent 401 errors for guest users. ProfileScreen refactors scattered isCreatorProfile null checks into a new isOwner getter for cleaner owner/view mode semantics. Test coverage added for guest user login state path.

Changes

Cohort / File(s) Summary
Auth State Guard
lib/controllers/auth_state_controller.dart
Adds conditional login-state guard around setUserProfileData() call in onInit, preventing unnecessary profile fetches and 401 errors for guest users.
Profile Screen Refactoring
lib/views/screens/profile_screen.dart
Introduces isOwner getter and consolidates scattered isCreatorProfile null checks throughout profile UI logic, affecting app bar actions, profile image source, name/username display, ratings, followers, follow behavior, email verification visibility, and story sections.
Auth Controller Tests
test/controllers/auth_state_controller_test.dart
Adds test case covering guest user login state path by simulating Unauthorized AppwriteException from account.get().

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A guard clause hops into the scene,
Guest users now safe, no 401 unseen,
Owner and viewer, now clearly defined,
Tests catch the edge case the team might have missed—
One small sprint, but logic so crisp! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes to profile_screen.dart introducing owner/view mode dichotomy appear unrelated to issue #746 (guarding account.get calls) and are addressed in a separate commit referencing issue #749. The profile_screen.dart changes should be submitted as a separate pull request or ensure they are explicitly linked to the same issue scope to maintain focused PR objectives.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately reflects the primary objective: guarding account.get() with a login state check to prevent unauthorized calls on app initialization.
Linked Issues check ✅ Passed The code changes in auth_state_controller.dart implement the required fix from issue #746 by conditionally calling setUserProfileData based on getLoginState, preventing 401 errors for guest users.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to prevent AuthStateController from triggering an unauthorized account.get() call during app initialization when the user is not logged in (fixing #746).

Changes:

  • Added an initialization guard in AuthStateController.onInit() before calling setUserProfileData().
  • Added a unit test asserting getLoginState returns false when Account.get() throws a 401.
  • Refactored ProfileScreen to use an isOwner getter for cleaner owner/public-view branching.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
lib/controllers/auth_state_controller.dart Adds a login-state guard around setUserProfileData() during controller init.
test/controllers/auth_state_controller_test.dart Adds a test for guest login-state behavior (401 → false).
lib/views/screens/profile_screen.dart Refactors repeated isCreatorProfile checks into an isOwner getter for readability.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +108 to +110
if (await getLoginState) {
await setUserProfileData();
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This PR changes AuthStateController.onInit() behavior, but tests only cover getLoginState directly. Please add a unit test that exercises onInit() for a guest user and asserts that profile initialization is skipped (i.e., setUserProfileData() is not invoked / no user DB reads happen).

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +252
// Restore stub for subsequent tests
when(mockAccount.get()).thenAnswer((_) => Future.value(mockUser));
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The stub reset at the end of this test is redundant because setUp() re-stubs mockAccount.get() before every test. Keeping it here makes the test order-dependent if future changes add setUpAll or modify setup behavior; prefer relying on setUp() (or add a tearDown()/reset() if needed).

Suggested change
// Restore stub for subsequent tests
when(mockAccount.get()).thenAnswer((_) => Future.value(mockUser));

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +110
if (await getLoginState) {
await setUserProfileData();
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

onInit now guards setUserProfileData() with getLoginState, but getLoginState itself calls account.get() (and setUserProfileData() calls account.get() again). This means the app still makes an unauthorized account.get() request for guest users (just swallowed), and authenticated users pay for two account.get() calls. Consider switching the guard to a session check that does not call account.get(), or refactor so setUserProfileData() can reuse the already-fetched appwriteUser instead of fetching again.

Suggested change
if (await getLoginState) {
await setUserProfileData();
}
await setUserProfileData();

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/controllers/auth_state_controller.dart`:
- Around line 108-110: The guard uses getLoginState which itself calls
account.get(), causing unauthorized or duplicate account.get() calls; change the
flow so the init guard does not call account.get(): either (A) refactor
getLoginState to return a local cached boolean (e.g. _isLoggedIn) or check a
non-network auth token/session flag instead of calling account.get(), or (B)
change the init sequence to call account.get() exactly once and pass its result
into setUserProfileData; update symbols getLoginState, setUserProfileData, and
any use of account.get() so unauthenticated startup never triggers account.get()
and authenticated startup calls account.get() only once.

In `@lib/views/screens/profile_screen.dart`:
- Around line 44-47: The isOwner predicate and initState public/owner branching
are inconsistent: change the getter to align with initState by making owner be
anything not explicitly true (bool get isOwner => widget.isCreatorProfile !=
true), and add a constructor/assert invariant to guarantee widget.creator is
non-null when isCreatorProfile == true (e.g. assert(widget.isCreatorProfile !=
true || widget.creator != null)) so initState and any dereferences of
widget.creator are safe and consistent with the new predicate.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf1dbe2 and d472396.

📒 Files selected for processing (3)
  • lib/controllers/auth_state_controller.dart
  • lib/views/screens/profile_screen.dart
  • test/controllers/auth_state_controller_test.dart

Comment on lines +108 to +110
if (await getLoginState) {
await setUserProfileData();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard still triggers account.get() for guest init path.

At Line 108, getLoginState is used as a guard, but getLoginState itself calls account.get() (Line 190). So unauthenticated startup still performs the unauthorized account request (and authenticated startup does two account.get() calls: Line 190 and Line 200). This does not fully meet the stated objective of preventing unauthorized account.get() on init.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/controllers/auth_state_controller.dart` around lines 108 - 110, The guard
uses getLoginState which itself calls account.get(), causing unauthorized or
duplicate account.get() calls; change the flow so the init guard does not call
account.get(): either (A) refactor getLoginState to return a local cached
boolean (e.g. _isLoggedIn) or check a non-network auth token/session flag
instead of calling account.get(), or (B) change the init sequence to call
account.get() exactly once and pass its result into setUserProfileData; update
symbols getLoginState, setUserProfileData, and any use of account.get() so
unauthenticated startup never triggers account.get() and authenticated startup
calls account.get() only once.

Comment on lines +44 to +47
/// Returns true if the current user is viewing their own profile (owner mode)
/// Returns false if viewing another user's profile (public view mode)
bool get isOwner => widget.isCreatorProfile == null;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

isOwner predicate can desync with init/data assumptions.

isOwner treats any non-null isCreatorProfile as public mode (Line 46), but initState only runs public-profile initialization when isCreatorProfile == true (Line 51). If isCreatorProfile is false, !isOwner branches can still dereference widget.creator! without aligned initialization/invariants.

Proposed fix (unify owner/public predicate and constructor invariant)
 class ProfileScreen extends StatefulWidget {
   final ResonateUser? creator;
 
   final bool? isCreatorProfile;
 
   ProfileScreen({super.key, this.creator, this.isCreatorProfile})
     : assert(
-        isCreatorProfile != true || (creator != null && creator.uid != null),
-        'creator and creator.uid are required when isCreatorProfile is true',
+        creator == null || creator.uid != null,
+        'creator.uid is required when viewing another user profile',
       );
@@
 class _ProfileScreenState extends State<ProfileScreen> {
-  bool get isOwner => widget.isCreatorProfile == null;
+  bool get isOwner => widget.creator == null;
@@
   void initState() {
     super.initState();
-    if (widget.isCreatorProfile == true) {
+    if (!isOwner) {
       WidgetsBinding.instance.addPostFrameCallback((_) async {
         await userProfileController.initializeProfile(widget.creator!.uid!);
       });
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/views/screens/profile_screen.dart` around lines 44 - 47, The isOwner
predicate and initState public/owner branching are inconsistent: change the
getter to align with initState by making owner be anything not explicitly true
(bool get isOwner => widget.isCreatorProfile != true), and add a
constructor/assert invariant to guarantee widget.creator is non-null when
isCreatorProfile == true (e.g. assert(widget.isCreatorProfile != true ||
widget.creator != null)) so initState and any dereferences of widget.creator are
safe and consistent with the new predicate.

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.

AuthStateController calls account.get() on init causing 401 for guest users

2 participants