Restrict exposure of full name to certain groups

AI-generated summary

mdoggydog proposes a new Discourse feature to restrict exposure of users’ full names to specific groups, aiming to balance public accessibility with privacy. While Discourse already handles public usernames and private emails, full names currently leak in search results, badge lists, and API responses—even when profiles are hidden. The proposed setting, “Restrict exposure of full name to groups,” would allow admins to define which user groups (e.g., TL1 members) can view full names, with others receiving null or omitted name fields. mdoggydog suggests this could be a more granular version of the existing “Enable names” setting. In a follow-up, mdoggydog reports beginning implementation: adding a site setting “Full names visible to groups,” a can_see_full_names? method in Guardian, and replacing SiteSetting.enable_names calls. The main challenge has been ensuring serializers properly pass scope parameters to enforce visibility rules. The goal is to fulfill a privacy promise to users and enable safe public site launch.

Background
We are trying to set up our site to strike a balance between open access and privacy concerns:

  1. The site is public overall; anonymous users can browse, and search engines can index it. Usernames are public.
  2. Real names (full name) and profiles are considered semi-public; they should only be exposed to other community members (not to webcrawlers or anonymous lurkers).
  3. Email addresses are considered completely private; only admins should have access to those (and access is monitored).

Discourse already takes care of (1) and (3) by default. (Yay!) We are having trouble achieving (2).

By disabling “Display name on posts” and enabling “Hide user profiles from public”, we get something that seems better-ish, but does not quite achieve (2). User-search results and Badge recipient lists still display full names.(*) And, even in places where the UI does not display the full names, the server is still sending them — e.g., in the JSON for a fetched topic, every post object still has the “name” (and “display_username”?) populated.

We want to make the promise to our users that “Your real name is only exposed to other community members” but we cannot do that if the server is leaking full names everywhere.

Proposed Feature
How about a “Restrict exposure of full name to groups” setting, with the following properties:

  • The setting value is an allowlist of groups (with some value that means “everyone, even anonymous users”).
  • If a query comes from a client session that matches against the allowlist, then the server responds with full names. Otherwise, any field that would bear a full name gets a null value (or is left out of the object, etc.)

I think that would take care of our (2) — and it would even allow us to set the bar for displaying real names at TL1 (versus TL0).

It occurs to me that what I am asking for might simply(:blush:) be a finer-grained version of the existing “Enable names” setting (if disabling that does what it promises on the server-side, and does not expose full names to the client). Maybe that would make this really easy to implement… :thinking:

Does this seem like a plausible feature for the Discourse core?

(Alternatively, does it seem achievable in a plugin? I’d rather see it in core, but I also want to be able to actually open our site to the public).

(*: Preventing anonymous users from doing user-searches and viewing badge recipient lists — and thus being able to trivially grab a list of all our users — is a whole 'nother topic, for another Topic.)

3 Likes

Follow-up: I have started working on an implementation of this. My basic approach is:

  • Add a new site setting, “Full names visible to groups” (i.e., “groups to which any user’s full name is visible”).
  • Add a new can_see_full_names? predicate to Guardian, which checks against the site setting.
  • Replace (many) instances of SiteSetting.enable_names with the can_see_full_names? predicate.

This has been mostly straightforward — the biggest snag has been serializers not forwarding their scope parameters, and that has turned into its own little subproject.

2 Likes