summary refs log tree commit diff
path: root/synapse/api/auth.py
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/api/auth.py')
-rw-r--r--synapse/api/auth.py40
1 files changed, 38 insertions, 2 deletions
diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index e3b8c3099a..adb9a776e0 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -14,15 +14,19 @@
 # limitations under the License.
 
 """This module contains classes for authenticating the user."""
+from nacl.exceptions import BadSignatureError
 
 from twisted.internet import defer
 
 from synapse.api.constants import EventTypes, Membership, JoinRules
 from synapse.api.errors import AuthError, Codes, SynapseError
-from synapse.util.logutils import log_function
 from synapse.types import RoomID, UserID, EventID
+from synapse.util.logutils import log_function
+from synapse.util.thirdpartyinvites import ThirdPartyInvites
+from unpaddedbase64 import decode_base64
 
 import logging
+import nacl.signing
 import pymacaroons
 
 logger = logging.getLogger(__name__)
@@ -31,6 +35,7 @@ logger = logging.getLogger(__name__)
 AuthEventTypes = (
     EventTypes.Create, EventTypes.Member, EventTypes.PowerLevels,
     EventTypes.JoinRules, EventTypes.RoomHistoryVisibility,
+    EventTypes.ThirdPartyInvite,
 )
 
 
@@ -341,7 +346,8 @@ class Auth(object):
                 pass
             elif join_rule == JoinRules.INVITE:
                 if not caller_in_room and not caller_invited:
-                    raise AuthError(403, "You are not invited to this room.")
+                    if not self._verify_third_party_invite(event, auth_events):
+                        raise AuthError(403, "You are not invited to this room.")
             else:
                 # TODO (erikj): may_join list
                 # TODO (erikj): private rooms
@@ -367,6 +373,31 @@ class Auth(object):
 
         return True
 
+    def _verify_third_party_invite(self, event, auth_events):
+        for key in ThirdPartyInvites.JOIN_KEYS:
+            if key not in event.content:
+                return False
+        token = event.content["token"]
+        invite_event = auth_events.get(
+            (EventTypes.ThirdPartyInvite, token,)
+        )
+        if not invite_event:
+            return False
+        try:
+            public_key = event.content["public_key"]
+            key_validity_url = event.content["key_validity_url"]
+            if invite_event.content["public_key"] != public_key:
+                return False
+            if invite_event.content["key_validity_url"] != key_validity_url:
+                return False
+            verify_key = nacl.signing.VerifyKey(decode_base64(public_key))
+            encoded_signature = event.content["signature"]
+            signature = decode_base64(encoded_signature)
+            verify_key.verify(token, signature)
+            return True
+        except (KeyError, BadSignatureError,):
+            return False
+
     def _get_power_level_event(self, auth_events):
         key = (EventTypes.PowerLevels, "", )
         return auth_events.get(key)
@@ -646,6 +677,11 @@ class Auth(object):
             if e_type == Membership.JOIN:
                 if member_event and not is_public:
                     auth_ids.append(member_event.event_id)
+                if ThirdPartyInvites.has_join_keys(event.content):
+                    key = (EventTypes.ThirdPartyInvite, event.content["token"])
+                    invite = current_state.get(key)
+                    if invite:
+                        auth_ids.append(invite.event_id)
             else:
                 if member_event:
                     auth_ids.append(member_event.event_id)