Skip to content

fix: prevent signup blocking invitation signups#5507

Closed
Zaimwa9 wants to merge 4 commits intomainfrom
fix/prevent-signup-blocking-invitation-signups
Closed

fix: prevent signup blocking invitation signups#5507
Zaimwa9 wants to merge 4 commits intomainfrom
fix/prevent-signup-blocking-invitation-signups

Conversation

@Zaimwa9
Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 commented May 29, 2025

Thanks for submitting a PR! Please check the boxes below:

  • I have added information to docs/ if required so people know about the feature!
  • I have filled in the "Changes" section below?
  • I have filled in the "How did you test this code" section below?
  • I have used a Conventional Commit title for this Pull Request

closes #5506

Changes

  • added email and link invitation checks in IsSignupAllowed permissions
  • Use the request error in the frontend

How did you test this code?

  • Added tests

To test:

  1. Run backend with "PREVENT_SIGNUP": "1",
  2. Share invitation link / invite with email a user
  3. Complete signup

https://www.loom.com/share/02c75a8dc28c4378b9856867c2ca7c85

@Zaimwa9 Zaimwa9 requested review from a team as code owners May 29, 2025 12:55
@Zaimwa9 Zaimwa9 requested review from emyller and tiagoapolo and removed request for a team May 29, 2025 12:55
@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs ⬜️ Ignored (Inspect) Visit Preview May 29, 2025 2:55pm
flagsmith-frontend-preview ⬜️ Ignored (Inspect) Visit Preview May 29, 2025 2:55pm
flagsmith-frontend-staging ⬜️ Ignored (Inspect) Visit Preview May 29, 2025 2:55pm

@github-actions github-actions Bot added front-end Issue related to the React Front End Dashboard api Issue related to the REST API labels May 29, 2025
@Zaimwa9 Zaimwa9 requested a review from khvn26 May 29, 2025 12:56
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2025

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-5507 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api-test:pr-5507 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-5507 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-5507 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-5507 Finished ✅ Results

@Zaimwa9 Zaimwa9 changed the title Fix: prevent signup blocking invitation signups fix: prevent signup blocking invitation signups May 29, 2025
@github-actions
Copy link
Copy Markdown
Contributor

Uffizzi Ephemeral Environment Deploying

☁️ https://app.uffizzi.com/github.com/Flagsmith/flagsmith/pull/5507

⚙️ Updating now by workflow run 15324374777.

What is Uffizzi? Learn more!

@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 97.65%. Comparing base (62c6ef5) to head (73e5711).
Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5507   +/-   ##
=======================================
  Coverage   97.65%   97.65%           
=======================================
  Files        1237     1238    +1     
  Lines       43580    43634   +54     
=======================================
+ Hits        42558    42612   +54     
  Misses       1022     1022           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread api/custom_auth/permissions.py
Comment on lines +35 to +40
try:
invite_link = InviteLink.objects.get(hash=invite_hash)
if not invite_link.is_expired:
return True
except InviteLink.DoesNotExist:
pass
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
try:
invite_link = InviteLink.objects.get(hash=invite_hash)
if not invite_link.is_expired:
return True
except InviteLink.DoesNotExist:
pass
try:
invite_link = InviteLink.objects.get(hash=invite_hash)
except InviteLink.DoesNotExist:
return False
return not invite_link.is_expired

This keeps only the code that is expected to fail within the try clause, and also returns False rather than None — if that's ideal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed to extract the is_expired check from the try/catch block - thanks.

Allow me to disagree on the False/None part. It should not be returning None as it would:

  • return true (allow-all, valid email, valid link)
  • surface a server/unknown error
  • if doesNotExist or is_expired => passes through the PermissionDenied.
    Which to me is the correct error to return.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Also for context, DRF will short-circuit to a 401 if authentication fails (via get_authenticators()) without explicitely raising an error

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the context.

Sorry I addressed the raise statement in another comment.

As per DRF documentation, it will automatically raise PermissionDenied when has_permission returns False. Having it manually raise feels like an anti-pattern. If you need to customize how DRF will present that exception to the HTTP response, you may set the attributes code and message to the permission class.

There's also this SO thread with examples.

Let me know if this helps.

Comment thread api/custom_auth/permissions.py Outdated


class IsSignupAllowed(AllowAny):
message = "Signing-up without a valid invitation is disabled. Please contact your administrator."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This message sounds too specific for a permission with a generic name. 🤔
Perhaps we should use it in the code branch within has_permission?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes I thought the same but that's actually the only purpose of this permission afaik:

  • PREVENT_SIGNUP = false => Always allowed
  • PREVENT_SIGNUP = true => Needs invitation or error

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see. In that case, just a minor tweak:

Suggested change
message = "Signing-up without a valid invitation is disabled. Please contact your administrator."
message = "Signing up without an invitation is disabled. Please contact your administrator."

except InviteLink.DoesNotExist:
pass

raise PermissionDenied(self.message)
Copy link
Copy Markdown
Contributor

@emyller emyller May 29, 2025

Choose a reason for hiding this comment

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

Following returning False above, DRF should already raise using the message attribute from the class on its own. 😉

@github-actions github-actions Bot added the fix label May 29, 2025
@Zaimwa9
Copy link
Copy Markdown
Contributor Author

Zaimwa9 commented May 29, 2025

Closed in favor of #5508

@Zaimwa9 Zaimwa9 closed this May 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API fix front-end Issue related to the React Front End Dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot invite users using invitation link

3 participants