Skip to content

SF-3730 Require authentication for SignalR notifications#3735

Merged
RaymondLuong3 merged 2 commits intomasterfrom
fix/SF-3730
Mar 26, 2026
Merged

SF-3730 Require authentication for SignalR notifications#3735
RaymondLuong3 merged 2 commits intomasterfrom
fix/SF-3730

Conversation

@pmachapman
Copy link
Copy Markdown
Collaborator

@pmachapman pmachapman commented Mar 10, 2026

This PR updates the SignalR notification hub to check that the user has access to the project they wish to subscribe to or send notifications to.

These permission checks are only performed on client calls to SignalR - all server calls to SignalR are performed via the functions in NotificationHubExtensions, which do not perform permission checks, as they are called primarily form background jobs.


Open with Devin

This change is Reviewable

@pmachapman pmachapman added the will require testing PR should not be merged until testers confirm testing is complete label Mar 10, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@Nateowami Nateowami added the e2e Run e2e tests for this pull request label Mar 10, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 10, 2026

Codecov Report

❌ Patch coverage is 0% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.29%. Comparing base (3bb4468) to head (74773bf).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...L.XForge.Scripture/Services/NotificationHubBase.cs 0.00% 18 Missing ⚠️
...ntApp/src/app/core/project-notification.service.ts 0.00% 1 Missing ⚠️
...ate/draft-generation/draft-notification.service.ts 0.00% 1 Missing ⚠️
....XForge.Scripture/Services/DraftNotificationHub.cs 0.00% 1 Missing ⚠️
...c/SIL.XForge.Scripture/Services/NotificationHub.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3735      +/-   ##
==========================================
- Coverage   81.32%   81.29%   -0.03%     
==========================================
  Files         620      621       +1     
  Lines       39100    39114      +14     
  Branches     6373     6377       +4     
==========================================
  Hits        31798    31798              
- Misses       6317     6331      +14     
  Partials      985      985              

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

@marksvc marksvc self-assigned this Mar 20, 2026
Copy link
Copy Markdown
Collaborator

@marksvc marksvc left a comment

Choose a reason for hiding this comment

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

@marksvc reviewed 3 files and all commit messages, and made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on pmachapman).


src/SIL.XForge.Scripture/Services/NotificationHub.cs line 7 at r3 (raw file):

namespace SIL.XForge.Scripture.Services;

public class NotificationHub(IRealtimeService realtimeService)

Is it true that if Alice and Bob subscribe to receive notifications on project X, that from her frontend, Alice can cause Bob to receive build progress notifications regarding project X?

That's not the end of the world. But I don't think that's what we are going for.

From what I'm gathering, it sounds like the NotificationHub.cs NotifyFoo() methods are never called by either the current frontend or current backend. They are just there to satisfy the SignalR structure. And if remove INotifier from NotificationHub, we might (?) still satisfy the SignalR structure, but frontend clients will not be able to call the NotifyFoo methods. Furthermore, we could probably delete the bodies of the NotifyFoo methods here and they could be implemented as no-op methods.

If this is so, I don't like that the current NotifyFoo methods (1) look like they do something, but aren't supposed to be used to do anything, and (2) are providing an unnecessary surface to defend.

This is new to me. Can you tell me if I'm way off base? Maybe you considered what I described but favoured the proposed way to set up the code?

Copy link
Copy Markdown
Collaborator Author

@pmachapman pmachapman left a comment

Choose a reason for hiding this comment

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

@pmachapman made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on marksvc).


src/SIL.XForge.Scripture/Services/NotificationHub.cs line 7 at r3 (raw file):

Is it true that if Alice and Bob subscribe to receive notifications on project X, that from her frontend, Alice can cause Bob to receive build progress notifications regarding project X?

Yes, that is by design, as the starting of a build should display to other users on the project. It is the same for applying a draft.

From what I'm gathering, it sounds like the NotificationHub.cs NotifyFoo() methods are never called by either the current frontend or current backend.

These are called by the frontend via SignalR (see a basic example of the structure at: https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-10.0&tabs=visual-studio#create-a-signalr-hub). The backend calls the extension methods (which I have named the same).

@marksvc
Copy link
Copy Markdown
Collaborator

marksvc commented Mar 24, 2026

src/SIL.XForge.Scripture/Services/NotificationHub.cs line 7 at r3 (raw file):

Previously, pmachapman (Peter Chapman) wrote…

Is it true that if Alice and Bob subscribe to receive notifications on project X, that from her frontend, Alice can cause Bob to receive build progress notifications regarding project X?

Yes, that is by design, as the starting of a build should display to other users on the project. It is the same for applying a draft.

From what I'm gathering, it sounds like the NotificationHub.cs NotifyFoo() methods are never called by either the current frontend or current backend.

These are called by the frontend via SignalR (see a basic example of the structure at: https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-10.0&tabs=visual-studio#create-a-signalr-hub). The backend calls the extension methods (which I have named the same).

Thank you for that. I am having more of a look around on branch fix/SF-3730 but I can't find any frontend message sending to SignalR other than this.connection.send('subscribeToProject' in project-notification.service and draft-notification.service.ts.

I see code like

  setNotifyBuildProgressHandler(handler: any): void {
    this.connection.on('notifyBuildProgress', handler);

and

  private readonly notifyBuildProgressHandler = (projectId: string): void => {
    this.loadHistory(projectId);

Unless I should be looking at the C# code?

Can you help me find where in the frontend it sends messages to SignalR?

@pmachapman pmachapman removed the e2e Run e2e tests for this pull request label Mar 24, 2026
Copy link
Copy Markdown
Collaborator Author

@pmachapman pmachapman left a comment

Choose a reason for hiding this comment

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

@pmachapman made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on marksvc).


src/SIL.XForge.Scripture/Services/NotificationHub.cs line 7 at r3 (raw file):

Previously, marksvc wrote…

Thank you for that. I am having more of a look around on branch fix/SF-3730 but I can't find any frontend message sending to SignalR other than this.connection.send('subscribeToProject' in project-notification.service and draft-notification.service.ts.

I see code like

  setNotifyBuildProgressHandler(handler: any): void {
    this.connection.on('notifyBuildProgress', handler);

and

  private readonly notifyBuildProgressHandler = (projectId: string): void => {
    this.loadHistory(projectId);

Unless I should be looking at the C# code?

Can you help me find where in the frontend it sends messages to SignalR?

Sorry, I misspoke. The this.connection.on('notifyBuildProgress', handler); subscribes to the SignalR notification endpoint, corresponding to NotificationHub.NotifyBuildProgress(). The extension method NotificationHubExtensions.NotifyBuildProgress() calls NotificationHub.NotifyBuildProgress() via the SignalR library.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator Author

@pmachapman pmachapman left a comment

Choose a reason for hiding this comment

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

@pmachapman made 1 comment.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on marksvc).


src/SIL.XForge.Scripture/Services/NotificationHub.cs line 7 at r3 (raw file):

Previously, pmachapman (Peter Chapman) wrote…

Sorry, I misspoke. The this.connection.on('notifyBuildProgress', handler); subscribes to the SignalR notification endpoint, corresponding to NotificationHub.NotifyBuildProgress(). The extension method NotificationHubExtensions.NotifyBuildProgress() calls NotificationHub.NotifyBuildProgress() via the SignalR library.

OK scrap that. Turns out they weren't necessary.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator

@marksvc marksvc left a comment

Choose a reason for hiding this comment

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

@marksvc reviewed 7 files and all commit messages, made 1 comment, and resolved 1 discussion.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on pmachapman).


src/SIL.XForge.Scripture/Services/NotificationHubBase.cs line 58 at r3 (raw file):

        // Ensure the user is on the project, and has a Paratext role
        if (!project.UserRoles.TryGetValue(userId, out string role) || !SFProjectRole.IsParatextRole(role))

Why the requirement to also have a Paratext role?

Copy link
Copy Markdown
Collaborator Author

@pmachapman pmachapman left a comment

Choose a reason for hiding this comment

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

@pmachapman made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on marksvc).


src/SIL.XForge.Scripture/Services/NotificationHubBase.cs line 58 at r3 (raw file):

Previously, marksvc wrote…

Why the requirement to also have a Paratext role?

Only Paratext users can send/receive to Paratext.

@RaymondLuong3 RaymondLuong3 merged commit 3685f14 into master Mar 26, 2026
23 of 24 checks passed
@RaymondLuong3 RaymondLuong3 deleted the fix/SF-3730 branch March 26, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

will require testing PR should not be merged until testers confirm testing is complete

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants