Only allow users matching the team invite to accept, if the invite was specified for a user (rather than an email)

This commit is contained in:
Joseph Schorr 2014-09-12 14:29:01 -04:00
parent c5ca46a14b
commit 10faa7de84
7 changed files with 24 additions and 21 deletions

View file

@ -1988,6 +1988,12 @@ def delete_team_invite(code, user=None):
def confirm_team_invite(code, user): def confirm_team_invite(code, user):
found = lookup_team_invite(code) found = lookup_team_invite(code)
# If the invite is for a specific user, we have to confirm that here.
if found.user is not None and found.user != user:
message = """This invite is intended for user "%s".
Please login to that account and try again.""" % found.user.username
raise DataModelException(message)
# Add the user to the team. # Add the user to the team.
try: try:
add_user_to_team(user, found.team) add_user_to_team(user, found.team)

View file

@ -11,10 +11,7 @@ from util.useremails import send_org_invite_email
from util.gravatar import compute_hash from util.gravatar import compute_hash
def try_accept_invite(code, user): def try_accept_invite(code, user):
try: (team, inviter) = model.confirm_team_invite(code, user)
(team, inviter) = model.confirm_team_invite(code, user)
except model.DataModelException:
return None
model.delete_matching_notifications(user, 'org_team_invite', code=code) model.delete_matching_notifications(user, 'org_team_invite', code=code)
@ -355,10 +352,7 @@ class TeamMemberInvite(ApiResource):
@require_user_admin @require_user_admin
def delete(self, code): def delete(self, code):
""" Delete an existing member of a team. """ """ Delete an existing member of a team. """
try: (team, inviter) = model.delete_team_invite(code, get_authenticated_user())
(team, inviter) = model.delete_team_invite(code, get_authenticated_user())
except model.DataModelException:
raise NotFound()
model.delete_matching_notifications(get_authenticated_user(), 'org_team_invite', code=code) model.delete_matching_notifications(get_authenticated_user(), 'org_team_invite', code=code)

View file

@ -215,7 +215,10 @@ class User(ApiResource):
if parsed_invite is not None: if parsed_invite is not None:
if parsed_invite[0] == 'teaminvite': if parsed_invite[0] == 'teaminvite':
# Add the user to the team. # Add the user to the team.
try_accept_invite(invite_code, new_user) try:
try_accept_invite(invite_code, new_user)
except model.DataModelException:
pass
return 'Created', 201 return 'Created', 201
except model.TooManyUsersException as ex: except model.TooManyUsersException as ex:

View file

@ -2785,9 +2785,9 @@ function ConfirmInviteCtrl($scope, $location, UserService, ApiService, Notificat
ApiService.acceptOrganizationTeamInvite(null, params).then(function(resp) { ApiService.acceptOrganizationTeamInvite(null, params).then(function(resp) {
NotificationService.update(); NotificationService.update();
$location.path('/organization/' + resp.org + '/teams/' + resp.team); $location.path('/organization/' + resp.org + '/teams/' + resp.team);
}, function() { }, function(resp) {
$scope.loading = false; $scope.loading = false;
$scope.invalid = true; $scope.invalid = ApiService.getErrorMessage(resp, 'Invalid confirmation code');
}); });
} }
}); });

View file

@ -7,7 +7,7 @@
</div> </div>
<div class="quay-spinner" ng-show="!user.anonymous && loading"></div> <div class="quay-spinner" ng-show="!user.anonymous && loading"></div>
<div class="alert alert-danger" ng-show="!user.anonymous && invalid"> <div class="alert alert-danger" ng-show="!user.anonymous && invalid">
Invalid confirmation code {{ invalid }}
</div> </div>
</div> </div>
</div> </div>

View file

@ -3518,25 +3518,25 @@ class TestTeamMemberInvite(ApiTestCase):
self._run_test('PUT', 401, None, None) self._run_test('PUT', 401, None, None)
def test_put_freshuser(self): def test_put_freshuser(self):
self._run_test('PUT', 404, 'freshuser', None) self._run_test('PUT', 400, 'freshuser', None)
def test_put_reader(self): def test_put_reader(self):
self._run_test('PUT', 404, 'reader', None) self._run_test('PUT', 400, 'reader', None)
def test_put_devtable(self): def test_put_devtable(self):
self._run_test('PUT', 404, 'devtable', None) self._run_test('PUT', 400, 'devtable', None)
def test_delete_anonymous(self): def test_delete_anonymous(self):
self._run_test('DELETE', 401, None, None) self._run_test('DELETE', 401, None, None)
def test_delete_freshuser(self): def test_delete_freshuser(self):
self._run_test('DELETE', 404, 'freshuser', None) self._run_test('DELETE', 400, 'freshuser', None)
def test_delete_reader(self): def test_delete_reader(self):
self._run_test('DELETE', 404, 'reader', None) self._run_test('DELETE', 400, 'reader', None)
def test_delete_devtable(self): def test_delete_devtable(self):
self._run_test('DELETE', 404, 'devtable', None) self._run_test('DELETE', 400, 'devtable', None)
class TestSuperUserList(ApiTestCase): class TestSuperUserList(ApiTestCase):

View file

@ -891,7 +891,7 @@ class TestAcceptTeamMemberInvite(ApiTestCase):
# Verify the accept now fails. # Verify the accept now fails.
self.putResponse(TeamMemberInvite, self.putResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token), params=dict(code=invites[0].invite_token),
expected_code=404) expected_code=400)
@ -914,7 +914,7 @@ class TestDeclineTeamMemberInvite(ApiTestCase):
self.deleteResponse(TeamMemberInvite, self.deleteResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token), params=dict(code=invites[0].invite_token),
expected_code=404) expected_code=400)
def test_decline(self): def test_decline(self):
@ -942,7 +942,7 @@ class TestDeclineTeamMemberInvite(ApiTestCase):
# Make sure the invite was deleted. # Make sure the invite was deleted.
self.deleteResponse(TeamMemberInvite, self.deleteResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token), params=dict(code=invites[0].invite_token),
expected_code=404) expected_code=400)
class TestDeleteOrganizationTeamMember(ApiTestCase): class TestDeleteOrganizationTeamMember(ApiTestCase):