Skip to content

Commit 299a941

Browse files
accept proof of invitation from a new user only if the userId is unique among team members
1 parent 96c3ad5 commit 299a941

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

packages/auth/src/team/Team.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -554,8 +554,13 @@ export class Team extends EventEmitter<TeamEvents> {
554554
return invitations.validate(proof, invitation)
555555
}
556556

557-
/** Check if username is not used by any other person within the team. */
558-
public validateUserName = (userName: string) => {
557+
/** Check if userId and userName are not used by any other member within the team. */
558+
public validateUser = (userId: string, userName: string) => {
559+
const memberWithSameUserId = this.members().find(member => member.userId == userId)
560+
if (memberWithSameUserId != undefined) {
561+
return invitations.fail('userId is not unique within the team.')
562+
}
563+
559564
const memberWithSameUserName = this.members().find(member =>
560565
member.userName.toLowerCase() == userName.toLowerCase()
561566
)
@@ -575,8 +580,8 @@ export class Team extends EventEmitter<TeamEvents> {
575580
const invitationValidation = this.validateInvitation(proof)
576581
if (!invitationValidation.isValid) throw invitationValidation.error
577582

578-
const userNameValidation = this.validateUserName(userName)
579-
if (!userNameValidation.isValid) throw userNameValidation.error
583+
const userValidation = this.validateUser(memberKeys.name, userName)
584+
if (!userValidation.isValid) throw userValidation.error
580585

581586
const { id } = proof
582587

packages/auth/src/team/test/invitations.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,42 @@ describe('Team', () => {
274274
alice.team.admitMember(proofOfInvitation, bob.user.keys, alice.user.userName)
275275
}
276276

277-
// 👎 But the invitation is rejected because it the username is not unique
277+
// 👎 But the invitation is rejected because the username is not unique
278278
expect(tryToAdmitBob).toThrowError('Username is not unique within the team.')
279279

280280
// ❌ 👨🏻‍🦲 Bob is not on the team
281281
expect(alice.team.has(bob.userId)).toBe(false)
282282
})
283283

284+
it("won't accept proof of invitation with a userId that is not unique", () => {
285+
const { alice, eve } = setup('alice', { user: 'eve', member: false })
286+
287+
// 👩🏾 Alice invites 🦹‍♀️ Eve by sending her a random secret key
288+
const { seed } = alice.team.inviteMember()
289+
290+
// 🦹‍♀️ Eve accepts the invitation
291+
const proofOfInvitation = generateProof(seed)
292+
293+
// 🦹‍♀️ Eve prepares keys using Alice's userId
294+
const keysWithAliceUserId = {
295+
...eve.user.keys,
296+
name: alice.userId
297+
}
298+
299+
// 🦹‍♀️ Eve shows 👩🏾 Alice her proof of invitation, but uses Alice's userId
300+
const tryToAdmitEve = () => {
301+
alice.team.admitMember(proofOfInvitation, keysWithAliceUserId, eve.user.userName)
302+
}
303+
304+
// 👎 But the invitation is rejected because the userId is not unique
305+
expect(tryToAdmitEve).toThrowError('userId is not unique within the team.')
306+
307+
// ❌ 🦹‍♀️ Eve is not on the team
308+
expect(alice.team.has(eve.userId)).toBe(false)
309+
expect(alice.team.state.members.filter(({ userId }) => alice.userId)).toHaveLength(1)
310+
expect(alice.team.members(alice.userId).userName == alice.userName).toBe(true)
311+
})
312+
284313
describe('devices', () => {
285314
it('creates and accepts an invitation for a device', () => {
286315
const { alice: aliceLaptop } = setup('alice')

packages/auth/src/team/validate.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,19 @@ const validators: TeamStateValidatorSet = {
113113
return VALID
114114
},
115115

116-
/** Check if the username is not used by any other person within the team */
117-
mustBeUniqueUsername(...args) {
116+
/** Check if userId and userName are not used by any other member within the team */
117+
mustBeUniqueUserNameAndUserId(...args) {
118118
const [previousState, link] = args
119119
if (link.body.type === 'ADMIT_MEMBER') {
120-
const { userName } = link.body.payload
120+
const { userName, memberKeys } = link.body.payload
121+
122+
const memberWithSameUserId = previousState.members.find(member =>
123+
member.userId == memberKeys.name
124+
)
125+
if (memberWithSameUserId != undefined) {
126+
return fail('userId is not unique within the team.', ...args)
127+
}
128+
121129
const memberWithSameUserName = previousState.members.find(member =>
122130
member.userName.toLowerCase() == userName.toLowerCase()
123131
)

0 commit comments

Comments
 (0)