Skip to content

Commit f0d6fbc

Browse files
authored
Merge pull request #108 from local-first-web/fix-join
2 parents eec3c0c + 36cf7ce commit f0d6fbc

File tree

5 files changed

+32
-10
lines changed

5 files changed

+32
-10
lines changed

packages/auth-provider-automerge-repo/src/AuthProvider.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ export class AuthProvider extends EventEmitter<AuthProviderEvents> {
255255
/**
256256
* Creates a private share for a team we're already a member of.
257257
*/
258-
public async addTeam(team: Auth.Team) {
258+
public async addTeam(team: Auth.Team, teamKeyring = team.teamKeyring()) {
259259
const shareId = getShareId(team)
260260

261261
if (this.hasTeam(shareId)) {
@@ -269,6 +269,7 @@ export class AuthProvider extends EventEmitter<AuthProviderEvents> {
269269
shareId,
270270
team,
271271
documentIds: new Set(),
272+
teamKeyring,
272273
})
273274

274275
// persist our state now and whenever the team changes
@@ -469,16 +470,16 @@ export class AuthProvider extends EventEmitter<AuthProviderEvents> {
469470
this.#connections.set([shareId, peerId], connection)
470471

471472
connection
472-
.on('joined', async ({ team, user }) => {
473+
.on('joined', async ({ team, user, teamKeyring }) => {
473474
// When we successfully join a team, the connection gives us the team graph and the user's
474475
// info (including keys).
475476

476477
// When we're joining as a new device for an existing user, this is how we get the user's id and keys.
477478
this.#user = user
478479
this.#log = log.extend(user.userName)
479480

480-
// Create a share with this team
481-
await this.addTeam(team)
481+
// Create a share with this team and the full team keys
482+
await this.addTeam(team, teamKeyring)
482483

483484
// remove the used invitation as we no longer need it & don't want to present it to others
484485
this.#invitations.delete(shareId)
@@ -640,7 +641,10 @@ export class AuthProvider extends EventEmitter<AuthProviderEvents> {
640641
? ({
641642
shareId,
642643
encryptedTeam: share.team.save(),
643-
encryptedTeamKeys: encryptBytes(share.team.teamKeyring(), this.#device.keys.secretKey),
644+
encryptedTeamKeys: encryptBytes(
645+
{ ...share.teamKeyring, ...share.team.teamKeyring() },
646+
this.#device.keys.secretKey
647+
),
644648
documentIds,
645649
} as SerializedShare)
646650
: { shareId, documentIds }

packages/auth-provider-automerge-repo/src/test/AuthProvider.test.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,31 @@ describe('auth provider for automerge-repo', () => {
260260
teardown()
261261
})
262262

263-
it('persists local context and team state', async () => {
263+
it('persists local context and team state (including the complete keyring)', async () => {
264264
const {
265-
users: { alice, bob },
265+
users: { alice, bob, charlie },
266266
teardown,
267-
} = setup(['alice', 'bob'])
267+
} = setup(['alice', 'bob', 'charlie'])
268268

269269
const aliceTeam = Auth.createTeam('team A', alice.context)
270270
await alice.authProvider.addTeam(aliceTeam)
271271

272+
// Alice sends Charlie an invitation
273+
const { seed: charlieInvite } = aliceTeam.inviteMember()
274+
275+
// Charlie uses the invitation to join
276+
await charlie.authProvider.addInvitation({
277+
shareId: getShareId(aliceTeam),
278+
invitationSeed: charlieInvite,
279+
})
280+
281+
// they're able to authenticate and sync
282+
await authenticated(alice, charlie)
283+
await synced(alice, charlie) // ✅
284+
285+
// Alice boots charlie
286+
aliceTeam.remove(charlie.user.userId)
287+
272288
// Alice sends Bob an invitation
273289
const { seed: bobInvite } = aliceTeam.inviteMember()
274290

packages/auth-provider-automerge-repo/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export type PublicShare = {
3434
export type PrivateShare = PublicShare & {
3535
/** The team that is used for enforcing authenticated access to this share */
3636
team: Auth.Team
37+
teamKeyring: Auth.Keyring
3738
}
3839

3940
export const isPrivateShare = (share: Share): share is PrivateShare =>

packages/auth/src/connection/Connection.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ export class Connection extends EventEmitter<ConnectionEvents> {
229229

230230
// We join the team, which adds our device to the team graph.
231231
team.join(teamKeyring)
232-
this.emit('joined', { team, user })
232+
this.emit('joined', { team, user, teamKeyring })
233233
return { user, team }
234234
}),
235235

packages/auth/src/connection/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
Base58,
55
Hash,
66
KeyScope,
7+
Keyring,
78
Keyset,
89
SyncState,
910
UnixTimestamp,
@@ -43,7 +44,7 @@ export type ConnectionEvents = {
4344
* this is how we get the user's keys.) This event gives the application a chance to persist the
4445
* team graph and the user's info.
4546
*/
46-
joined: ({ team, user }: { team: Team; user: UserWithSecrets }) => void
47+
joined: ({ team, user }: { team: Team; user: UserWithSecrets; teamKeyring: Keyring }) => void
4748

4849
/** The team graph has been updated. This event gives the application a chance to persist the changes. */
4950
updated: () => void

0 commit comments

Comments
 (0)