Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add options to prevent users from changing their profile. #7096

Merged
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions changelog.d/7096.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add options to prevent users from changing their profile or associated 3PIDs.
23 changes: 23 additions & 0 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,29 @@ account_threepid_delegates:
#email: https://example.com # Delegate email sending to example.com
#msisdn: http://localhost:8090 # Delegate SMS sending to this local process

# Whether users are allowed to change their displayname after it has
# been initially set. Useful when provisioning users based on the
# contents of a third-party directory.
#
# Does not apply to server administrators. Defaults to 'true'
#
#enable_set_displayname: false

# Whether users are allowed to change their avatar after it has been
# initially set. Useful when provisioning users based on the contents
# of a third-party directory.
#
# Does not apply to server administrators. Defaults to 'true'
#
#enable_set_avatar_url: false

# Whether users can change the 3PIDs associated with their accounts
# (email address and msisdn).
#
# Defaults to 'true'
#
#enable_3pid_changes: false

# Users who register on this homeserver will automatically be joined
# to these rooms
#
Expand Down
27 changes: 27 additions & 0 deletions synapse/config/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ def read_config(self, config, **kwargs):
raise ConfigError("Invalid auto_join_rooms entry %s" % (room_alias,))
self.autocreate_auto_join_rooms = config.get("autocreate_auto_join_rooms", True)

self.enable_set_displayname = config.get("enable_set_displayname", True)
self.enable_set_avatar_url = config.get("enable_set_avatar_url", True)
self.enable_3pid_changes = config.get("enable_3pid_changes", True)

self.disable_msisdn_registration = config.get(
"disable_msisdn_registration", False
)
Expand Down Expand Up @@ -330,6 +334,29 @@ def generate_config_section(self, generate_secrets=False, **kwargs):
#email: https://example.com # Delegate email sending to example.com
#msisdn: http://localhost:8090 # Delegate SMS sending to this local process

# Whether users are allowed to change their displayname after it has
# been initially set. Useful when provisioning users based on the
# contents of a third-party directory.
#
# Does not apply to server administrators. Defaults to 'true'
#
#enable_set_displayname: false

# Whether users are allowed to change their avatar after it has been
# initially set. Useful when provisioning users based on the contents
# of a third-party directory.
#
# Does not apply to server administrators. Defaults to 'true'
#
#enable_set_avatar_url: false
dklimpel marked this conversation as resolved.
Show resolved Hide resolved

# Whether users can change the 3PIDs associated with their accounts
# (email address and msisdn).
#
# Defaults to 'true'
#
#enable_3pid_changes: false

# Users who register on this homeserver will automatically be joined
# to these rooms
#
Expand Down
16 changes: 16 additions & 0 deletions synapse/handlers/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,15 @@ def set_displayname(self, target_user, requester, new_displayname, by_admin=Fals
if not by_admin and target_user != requester.user:
raise AuthError(400, "Cannot set another user's displayname")

if not by_admin and not self.hs.config.enable_set_displayname:
profile = yield self.store.get_profileinfo(target_user.localpart)
if profile.display_name:
raise SynapseError(
400,
"Changing display name is disabled on this server",
Codes.FORBIDDEN,
)

if len(new_displayname) > MAX_DISPLAYNAME_LEN:
raise SynapseError(
400, "Displayname is too long (max %i)" % (MAX_DISPLAYNAME_LEN,)
Expand Down Expand Up @@ -218,6 +227,13 @@ def set_avatar_url(self, target_user, requester, new_avatar_url, by_admin=False)
if not by_admin and target_user != requester.user:
raise AuthError(400, "Cannot set another user's avatar_url")

if not by_admin and not self.hs.config.enable_set_avatar_url:
profile = yield self.store.get_profileinfo(target_user.localpart)
if profile.avatar_url:
raise SynapseError(
400, "Changing avatar is disabled on this server", Codes.FORBIDDEN
)

if len(new_avatar_url) > MAX_AVATAR_URL_LEN:
raise SynapseError(
400, "Avatar URL is too long (max %i)" % (MAX_AVATAR_URL_LEN,)
Expand Down
16 changes: 16 additions & 0 deletions synapse/rest/client/v2_alpha/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,11 @@ async def on_GET(self, request):
return 200, {"threepids": threepids}

async def on_POST(self, request):
if not self.hs.config.enable_3pid_changes:
raise SynapseError(
400, "3PID changes are disabled on this server", Codes.FORBIDDEN
)

requester = await self.auth.get_user_by_req(request)
user_id = requester.user.to_string()
body = parse_json_object_from_request(request)
Expand Down Expand Up @@ -646,6 +651,11 @@ def __init__(self, hs):

@interactive_auth_handler
async def on_POST(self, request):
if not self.hs.config.enable_3pid_changes:
raise SynapseError(
400, "3PID changes are disabled on this server", Codes.FORBIDDEN
)

requester = await self.auth.get_user_by_req(request)
user_id = requester.user.to_string()
body = parse_json_object_from_request(request)
Expand Down Expand Up @@ -741,10 +751,16 @@ class ThreepidDeleteRestServlet(RestServlet):

def __init__(self, hs):
super(ThreepidDeleteRestServlet, self).__init__()
self.hs = hs
self.auth = hs.get_auth()
self.auth_handler = hs.get_auth_handler()

async def on_POST(self, request):
if not self.hs.config.enable_3pid_changes:
raise SynapseError(
400, "3PID changes are disabled on this server", Codes.FORBIDDEN
)

body = parse_json_object_from_request(request)
assert_params_in_dict(body, ["medium", "address"])

Expand Down
65 changes: 64 additions & 1 deletion tests/handlers/test_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from twisted.internet import defer

import synapse.types
from synapse.api.errors import AuthError
from synapse.api.errors import AuthError, SynapseError
from synapse.handlers.profile import MasterProfileHandler
from synapse.types import UserID

Expand Down Expand Up @@ -70,6 +70,7 @@ def register_query_handler(query_type, handler):
yield self.store.create_profile(self.frank.localpart)

self.handler = hs.get_profile_handler()
self.hs = hs

@defer.inlineCallbacks
def test_get_my_name(self):
Expand All @@ -90,6 +91,33 @@ def test_set_my_name(self):
"Frank Jr.",
)

# Set second time displayname
dklimpel marked this conversation as resolved.
Show resolved Hide resolved
yield self.handler.set_displayname(
self.frank, synapse.types.create_requester(self.frank), "Frank"
)

self.assertEquals(
(yield self.store.get_profile_displayname(self.frank.localpart)), "Frank",
)

@defer.inlineCallbacks
def test_set_my_name_if_disabled(self):
self.hs.config.enable_set_displayname = False

# Set first time displayname is allowed, if displayname is null
dklimpel marked this conversation as resolved.
Show resolved Hide resolved
yield self.store.set_profile_displayname(self.frank.localpart, "Frank")

self.assertEquals(
(yield self.store.get_profile_displayname(self.frank.localpart)), "Frank",
)

# Set second time displayname is forbidden
dklimpel marked this conversation as resolved.
Show resolved Hide resolved
d = self.handler.set_displayname(
self.frank, synapse.types.create_requester(self.frank), "Frank Jr."
)

yield self.assertFailure(d, SynapseError)

@defer.inlineCallbacks
def test_set_my_name_noauth(self):
d = self.handler.set_displayname(
Expand Down Expand Up @@ -147,3 +175,38 @@ def test_set_my_avatar(self):
(yield self.store.get_profile_avatar_url(self.frank.localpart)),
"http://my.server/pic.gif",
)

# Set second time avatar
dklimpel marked this conversation as resolved.
Show resolved Hide resolved
yield self.handler.set_avatar_url(
self.frank,
synapse.types.create_requester(self.frank),
"http://my.server/me.png",
)

self.assertEquals(
(yield self.store.get_profile_avatar_url(self.frank.localpart)),
"http://my.server/me.png",
)

@defer.inlineCallbacks
def test_set_my_avatar_if_disabled(self):
self.hs.config.enable_set_avatar_url = False

# Set first time avatar is allowed, if avatar is null
dklimpel marked this conversation as resolved.
Show resolved Hide resolved
yield self.store.set_profile_avatar_url(
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
self.frank.localpart, "http://my.server/me.png"
)

self.assertEquals(
(yield self.store.get_profile_avatar_url(self.frank.localpart)),
"http://my.server/me.png",
)

# Set second time avatar is forbidden
dklimpel marked this conversation as resolved.
Show resolved Hide resolved
d = self.handler.set_avatar_url(
self.frank,
synapse.types.create_requester(self.frank),
"http://my.server/pic.gif",
)

yield self.assertFailure(d, SynapseError)
Loading