Coder Social home page Coder Social logo

local-first-web / auth Goto Github PK

View Code? Open in Web Editor NEW
227.0 9.0 18.0 11.57 MB

Decentralized authentication and authorization for team collaboration, using a secure chain of cryptological signatures. (Formerly known as ๐ŸŒฎ Taco.)

License: MIT License

TypeScript 97.88% JavaScript 1.90% HTML 0.21%
cryptography peer-to-peer authentication authorization taco signature-chain team-collaboration local-first invitation seitan

auth's People

Contributors

bigdogwillfeed avatar brentkeller avatar dependabot[bot] avatar fredrodlima avatar herbcaudill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

auth's Issues

Sort out invitation failure responses

An invitation can fail to validate in several ways. Currently we have:

  • The invitation has been revoked
  • The invitation cannot be used again
  • The invitation has expired
  • IDs don't match
  • Signature provided is not valid
  • This invitation code doesn't match

Need to think about how an application would deal with each of these scenarios. At any rate we should use codes in addition to user-facing messages so the app can respond in a structured way

Clean up when a member's admission is reversed because of conflicts

Suppose Bob is removed from the group, and concurrently he invites Charlie, and Charlie joins the group. Charlie's admission is now invalid, because he was invited while concurrently Bob was being removed.

We currently handle this scenario correctly in that Charlie is no longer a member of the group. However we need to do some cleanup, and we currently don't have a way to do it. From #32 :

Currently if Charlie joins and then his invitation is annulled because of this kind of conflict, everyone else lives happily ever after, as if Charlie had never joined. But Charlie did join and so he has the signature chain, so his client app should be told to purge it (assuming it's well-behaved); and someone needs to rotate any keys he might have seen.

None of this is insoluble, but it does require me to rethink some things specific to this implementation.

  1. Currently when we're calculating the group's state from the chain, any actions that we've invalidated because of concurrency issues are simply discarded, and can't enter into the calculation. Instead, I think I'll need to mark those actions as invalid but still feed them through the reducer, so that e.g. an invalidated JOIN can be treated as a REMOVE.

  2. We don't have a way of alerting the group that certain keys need to be rotated. Currently key rotation only happens as part of a conscious REMOVE action by an admin. In the case where someone is removed not by an admin's action but as a mechanical result of the conflict resolution logic, there's not necessarily an admin around to rotate the keys. So we need a completely new mechanism to add an alert to the group's state that certain keys need to be rotated, and to react appropriately to that alert.

The plan:

  • In herbcaudill/crdx, rather than filtering out invalid links, mark them as invalid.
  • In the reducer (here in localfirst/auth) ignore invalid links altogether for now. Behavior should now be exactly same as before, and all tests should pass.

Now we're in a position to detect this scenario and surface it in team state.

  • In the reducer, when a member's admission is reversed because of conflicts (i.e. we see an ADMIT action that's marked invalid), add them to the list of removed users in team state. Now in this test we can test that Charlie knows he's been removed.
  • Add a pendingKeyRotations element to team state. When the reducer sees an invalid ADMIT as above, it should populate this with the keys Charlie could see, using the same logic as when we manually remove someone. Once these keys are rotated, the reducer should remove them from the list.
  • When state is updated and an admin sees anything in pendingKeyRotations, they should perform the key rotation.
  • #39

Connection: Test error conditions

While we're at it, this business with storing the error in context and then retrieving it and using it as details and storing something else in context.error is pretty gross.

Resolve module names with file extentions

I'm having difficulty using localfirst/auth within an Electron application (main process) because module names in imports aren't specified by the full path (e.g., .js or /index.js for directories). Would you welcome a pull request that adds these?

I agree it's a lot less elegant and pretty to look at than the way it's now, but it seems that that's how other typescript packages (e.g., libp2p) deal with the module resolution problem in Node.js.

What do you say?
Thanks!

Example with Y.js ?

I came here looking for a solution that allows access control for Y.Docs. You're library is really impressive and thank you for the dedicated work!

I'm not quite sure if Y.js can be used as a storage within crdx. An example with it in the Readme would certainly help making your library more accessible (and afterwards a link back from Y.js github page).

TLA causes issues with bundling

The top-level await await sodium.ready in @localfirst/crypto prevents this library from being bundled into cjs (even when dynamically imported) and thereby prevents it from being used in tools such as nexe, pkg or the newer node sea.

Would convering the crypto functions to async functions be a potential workaround?

Validate lockboxes

I don't think there's currently anything stopping me (at the graph level) from adding a lockbox for someone else. For example, I could make a fake lockbox containing user keys, addressed to someone else's device. I haven't thought through what the consequences of that might be -- it's not immediately clear how I might use that to my advantage. But it's probably not great, so should lock that down.

Enforce unique userIds and userNames

It's possible that I can currently join a team with an existing user's id and then impersonate them. Need to test this to be sure.

A "softer" attack would be to join a team with an existing user's user name, which is definitely possible, and could cause confusion.

The tricky part here would be to sort out collisions that happen concurrently.

Stagger key rotation when unwinding invalidated invitation

Multiple admins could simultaneously see that there are pending key rotations. It might make sense to add a random delay before rotating keys, or to come up with another way to ensure that these don't pile up.

This happens in Team.checkForPendingKeyRotations

Test plan:

  • Builds on the test "unwinds an invalidated admission" in sync.test.ts
  • Instead of just Alice, there are multiple admins
  • Assert that the team keys are only rotated once

Support arbitrary members admitting devices on behalf of other members

Currently a device can only be admitted by the user whose device it is. This works fine when peers connect directly to each other, but it doesn't work for star-shaped networks where every device connects to a sync server.

The reason it's set up this way is because the user has the user-level secret keys and can store them in a lockbox for the device.

But in a star-shaped topology like XDev uses, where everyone connects to a sync server instead of directly to each other, we need the server to be able to admit devices because a user's two devices will never connect directly.

We also need this to support "paper keys", in a situation where someone loses all their devices or their only device.

So we need another mechanism to get the user-level secret keys to the device.

One solution is to use the invitation code to generate a set of temporary keys. Bob on his laptop creates the invitation code, generates keys from it, and stores the user keys in a lockbox that can be opened by those keys.

Confirm that the signature on a link uses the author's signature key at the time of signing

Commented-out validator from auth\validate.ts :

  signatureKeyIsCorrect: (...args) => {
    const [prevState, link] = args
    const action = link.body
    const { type } = action

    // at root link, team doesn't yet have members
    if (type === ROOT) return VALID

    const { userId } = link.signed
    const author = select.member(prevState, userId)
    // TODO: test this case
    if (link.signed.key !== author.keys.signature) {
      const msg = `Wrong signature key. Link is signed with ${link.signed.key}, but ${userId}'s signature key is ${author.keys.signature}`
      return fail(msg, ...args)
    }
    return VALID
  },

Cover `joinedTheRightTeam` with a test

In the Connection protocol, we confirm that we haven't been spoofed into joining the wrong team: Once we've joined and gotten the full team history, we look for an invitation matching the secret invitation code we were given.

joinedTheRightTeam: (context, event) => {
// Make sure my invitation exists on the signature chain of the team I'm about to join.
// This check prevents an attack in which a fake team pretends to accept my invitation.
const { payload } = event as AcceptInvitationMessage
const { serializedGraph, teamKeyring } = payload
const state = getTeamState(serializedGraph, teamKeyring)
const { id } = this.myProofOfInvitation(context)
return select.hasInvitation(state, id)
},

This looks right but there are currently no tests covering this scenario.

Team objects and multiple devices

Many thanks for this library; it looks quite promising and I am very eager to try it out!

I had a few questions to which I could not find information in the documentation (apologies if it is there):

  1. I can see example code for how a team object is created by the original creator. When one joins an existing team, however, how does one generate the team object from one's invitation key or proof of invitation? I imagine that this would be necessary in order to encrypt to the team or else, if permissions allow, add new members.
  2. How can a user on one device add their other devices (keeping the same username)? Along the same lines, can one device revoke access to another if it is lost?
  3. And finally, just to confirm: how would this work in the browser? Would different browsers on the same machine each be its own "device" with its own keys?

Many thanks,
Julien Malard

Introduction to decentralized pattern library

Thanks so much for making such a concise and well-defined library for a problem that many p2p and local-first applications will face. What are you using it for? Or is it a hobby project?

I've been working on a decentralized pattern library called Decentralization, off the shelf with Simply Secure. We're currently working on a set of patterns and an introductory handbook for different ways identity can be done in decentralized applications. I'm focusing particularly on researching sets of pros and cons, and where particular libraries may be well suited for particular use cases (or not). I'm working on all this in the github repository, see disposible identity for an early-stage example.

I'd like to include taco and some of it's ideas, perhaps even creating a pattern for 'trust on first use' ... I'd also love to hear how you imagine this being used in applications and which kinds of applications it would be great for (and what are the pitfalls of this approach, as well)! Do you have any time to give more thoughts on broader applications of taco?

Multiple devices and team loading

Many thanks for this library; it looks quite promising and I am very eager to try it out!

I had a few questions to which I could not find information in the documentation (apologies if it is there):

  1. I can see example code for how a team object is created by the original creator. When one joins an existing team, however, how does one generate the team object from one's invitation key or proof of invitation? I imagine that this would be necessary in order to encrypt to the team or else, if permissions allow, add new members.
  2. How can a user on one device add their other devices (keeping the same username)? Along the same lines, can one device revoke access to another if it is lost?
  3. And finally, just to confirm: how would this work in the browser? Would different browsers on the same machine each be its own "device" with its own keys?

Many thanks,
Julien Malard

Sandbox syncing with removed members

We'll still open a connection and sync with someone who appears to have been removed from the team, in case they have information that would invalidate their removal (e.g. whoever removed them was concurrently demoted or removed themselves).

However, when we're syncing we don't want to provide them any information until we're sure they're still on the team. I think right now a removed member can sync up and continue to get updates to the signature chain.

What is the correct way to build the package?

Using yarn build results in the following:

tsc -p tsconfig.build.json
src/connection/Connection.ts(55,9): error TS2339: Property 'DEVICE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/device/create.ts(12,45): error TS2339: Property 'DEVICE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/constants.ts(19,43): error TS2339: Property 'TEAM' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/constants.ts(19,63): error TS2339: Property 'TEAM' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/constants.ts(20,44): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/constants.ts(22,17): error TS2339: Property 'EPHEMERAL' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/constants.ts(23,17): error TS2339: Property 'EPHEMERAL' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/decryptTeamGraph.ts(56,27): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Record<Hash, EncryptedLink>'.
  No index signature with a parameter of type 'string' was found on type 'Record<Hash, EncryptedLink>'.
src/team/decryptTeamGraph.ts(58,7): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Record<Hash, Link<TeamAction, TeamContext>>'.
  No index signature with a parameter of type 'string' was found on type 'Record<Hash, Link<TeamAction, TeamContext>>'.
src/team/decryptTeamGraph.ts(75,22): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'LinkMap'.
  No index signature with a parameter of type 'string' was found on type 'LinkMap'.
src/team/decryptTeamGraph.ts(78,24): error TS7006: Parameter 'hash' implicitly has an 'any' type.
src/team/serialize.ts(62,27): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Record<Hash, EncryptedLink>'.
  No index signature with a parameter of type 'string' was found on type 'Record<Hash, EncryptedLink>'.
src/team/serialize.ts(78,22): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'LinkMap'.
  No index signature with a parameter of type 'string' was found on type 'LinkMap'.
src/team/serialize.ts(81,24): error TS7006: Parameter 'hash' implicitly has an 'any' type.
src/team/Team.ts(188,43): error TS2339: Property 'DEVICE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(199,39): error TS2339: Property 'DEVICE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(323,51): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(365,55): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(393,55): error TS2339: Property 'DEVICE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(650,46): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(706,31): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/Team.ts(718,53): error TS2339: Property 'DEVICE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/transforms/removeMemberRole.ts(25,45): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
src/team/transforms/removeRole.ts(14,54): error TS2339: Property 'ROLE' does not exist on type '{ readonly GRAPH: "GRAPH"; readonly USER: "USER"; }'.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Review server permissions at the graph validation level

In servers.test.ts there are a bunch of tests demonstrating what a server can and cannot do, but it seems like those permissions are enforced by a combination of two things: (1) if a server isn't an admin (and it probably shouldn't ever be) then it can't add any links to the graph that are admin-only; and (2) there are checks in the Team public API that will throw if called by a server. But for example I think a server could add an 'ADD_DEVICE' link to the chain directly (without going through the public API).

As a side note we should probably enforce that a server can't ever be an admin.

taco-chat demo doesn't work when run by hand

The taco-chat demo is broken when I try to run it manually, but not when the Cypress tests run.

Steps to reproduce

  1. Check out main (42cb906 as of writing)
  2. pnpm install; pnpm build
  3. Confirm that Cypress tests pass
    • pnpm dev:cy:taco
    • run e.g. invitations suite
  4. Try to replicate the "Alice invites Bob" test:
    • pnpm dev:taco
    • Press "Invite members", "Invite", "Copy"
    • Show Bob's laptop
    • Press "Join team", paste invitation code, "Join"

What happens: Nothing

Screenshot 2024-04-28 at 6 57 16โ€ฏPM

What should happen: Bob should join Alice's team, they should both see each other in the list of members, and they should both show a team graph that includes Bob's admission.

Screenshot 2024-04-28 at 6 56 30โ€ฏPM

Trouble running auth demo

Today I tried running the demo and was unable to get anything working. I figured out I needed to install yarn and then install the dependencies, but was unable to proceed much further. I'm not particularly fluent in yarn (used to npm), so apologies if this is a case of me simply holding it wrong.

Here's the output from my machine:

nathan@Nathans-MacBook-Pro auth % node -v
v16.16.0
nathan@Nathans-MacBook-Pro auth % git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
nathan@Nathans-MacBook-Pro auth % git log -n 1
commit 49907d409d39a7b9c24f23f82fed1c3541ee05ed (HEAD -> main, origin/main, origin/HEAD)
Author: HerbCaudill <[email protected]>
Date:   Fri Sep 16 15:16:22 2022 +0200

    update for latest crdx with encrypted chain
nathan@Nathans-MacBook-Pro auth % yarn install
yarn install v1.22.19
[1/4] ๐Ÿ”  Resolving packages...
[2/4] ๐Ÿšš  Fetching packages...
[3/4] ๐Ÿ”—  Linking dependencies...
warning "lerna > @lerna/version > @lerna/github-client > @octokit/rest > @octokit/[email protected]" has unmet peer dependency "@octokit/core@>=3".
warning "workspace-aggregator-ab7c30cb-ba03-43b5-82a1-2042247dd175 > demo > @testing-library/[email protected]" has unmet peer dependency "@testing-library/dom@>=7.21.4".
warning "workspace-aggregator-ab7c30cb-ba03-43b5-82a1-2042247dd175 > demo > @windmill/react-ui > [email protected]" has incorrect peer dependency "react@^16.8.0".
[4/4] ๐Ÿ”จ  Building fresh packages...
success Saved lockfile.
โœจ  Done in 14.43s.
nathan@Nathans-MacBook-Pro auth % yarn dev
yarn run v1.22.19
$ run-p watch dev:demo
$ lerna run watch --stream --parallel
$ yarn --cwd demo && yarn --cwd demo dev
[1/4] ๐Ÿ”  Resolving packages...
โ  lerna notice cli v3.22.1
lerna info Executing command in 1 package: "yarn run watch"
success Already up-to-date.
@localfirst/auth: $ npm-watch
$ run-p dev:relay dev:serve
@localfirst/auth: No task specified. Will go through all possible tasks
$ cross-env DEBUG='lf*' DEBUG_COLORS=1 node ./scripts/start-relay-server.js
$ vite --port 3000
@localfirst/auth: [build] [nodemon] 2.0.15
@localfirst/auth: [postbuild] [nodemon] starting `npm run -s postbuild`
@localfirst/auth: [build] [nodemon] starting `npm run -s build`
  lf:relay:8080 version 3.6.0 +0ms
๐ŸŸ โฏ Listening at http://localhost:8080
  lf:relay:8080 ready +6ms
@localfirst/auth: [postbuild] tscpaths --project /Users/nathan/Documents/Projects/local-first-web/auth/packages/auth/tsconfig.build.json --src /Users/nathan/Documents/Projects/local-first-web/auth/packages/auth/src --out /Users/nathan/Documents/Projects/local-first-web/auth/packages/auth/dist
@localfirst/auth: [postbuild] Replaced 0 paths in 0 files
@localfirst/auth: [postbuild] [nodemon] clean exit - waiting for changes before restart

  vite v2.9.0 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 1055ms.

โœ˜ [ERROR] [plugin vite:dep-scan] Failed to resolve entry for package "@localfirst/auth". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "@localfirst/auth". The package may have incorrect main/module/exports specified in its package.json.

    ../node_modules/vite/dist/node/chunks/dep-8db0e223.js:38291:10:
      38291 โ”‚     throw new Error(`Failed to resolve entry for package "${id}". ` +
            โ•ต           ^

    at packageEntryFailure (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:38291:11)
    at resolvePackageEntry (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:38287:9)
    at tryNodeResolve (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:38094:20)
    at Context.resolveId (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:37902:28)
    at Object.resolveId (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:36470:55)
    at async resolve (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:36682:26)
    at async /Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:36839:34
    at async callback (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:918:28)
    at async handleRequest (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:698:30)

  This error came from the "onResolve" callback registered here:

    ../node_modules/vite/dist/node/chunks/dep-8db0e223.js:36829:18:
      36829 โ”‚             build.onResolve({
            โ•ต                   ~~~~~~~~~

    at setup (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:36829:19)
    at handlePlugins (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:840:23)
    at Object.buildOrServe (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:1134:7)
    at /Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:2076:17
    at new Promise (<anonymous>)
    at Object.build (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:2075:14)
    at Object.build (/Users/nathan/Documents/Projects/local-first-web/auth/node_modules/esbuild/lib/main.js:1924:51)
    at /Users/nathan/Documents/Projects/local-first-web/auth/node_modules/vite/dist/node/chunks/dep-8db0e223.js:36630:54
    at Array.map (<anonymous>)

  The plugin "vite:dep-scan" was triggered by this import

    src/components/App.tsx:1:22:
      1 โ”‚ import * as auth from '@localfirst/auth'

... [same error repeats many times]
^C
nathan@Nathans-MacBook-Pro auth % yarn dev:cy
yarn run v1.22.19
$ run-p watch dev:cy:demo
$ yarn --cwd demo && yarn --cwd demo dev:cy
$ lerna run watch --stream --parallel
[1/4] ๐Ÿ”  Resolving packages...
โ  lerna notice cli v3.22.1
lerna info Executing command in 1 package: "yarn run watch"
@localfirst/auth: $ npm-watch
success Already up-to-date.
@localfirst/auth: No task specified. Will go through all possible tasks
$ cross-env BROWSER=none CYPRESS_REMOTE_DEBUGGING_PORT=9222 run-p dev test:cy
@localfirst/auth: [postbuild] [nodemon] 2.0.15
@localfirst/auth: [postbuild] [nodemon] starting `npm run -s postbuild`
@localfirst/auth: [build] [nodemon] starting `npm run -s build`
$ run-p dev:relay dev:serve
$ cypress open
@localfirst/auth: [postbuild] tscpaths --project /Users/nathan/Documents/Projects/local-first-web/auth/packages/auth/tsconfig.build.json --src /Users/nathan/Documents/Projects/local-first-web/auth/packages/auth/src --out /Users/nathan/Documents/Projects/local-first-web/auth/packages/auth/dist
@localfirst/auth: [postbuild] Replaced 0 paths in 0 files
@localfirst/auth: [postbuild] [nodemon] clean exit - waiting for changes before restart
$ cross-env DEBUG='lf*' DEBUG_COLORS=1 node ./scripts/start-relay-server.js
$ vite --port 3000
  lf:relay:8080 version 3.6.0 +0ms
๐ŸŸ โฏ Listening at http://localhost:8080
  lf:relay:8080 ready +6ms

  vite v2.9.0 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 1021ms.

@localfirst/auth: [build] src/connection/Connection.ts(125,27): error TS2339: Property 'userId' does not exist on type 'UserWithSecrets'.
@localfirst/auth: [build] src/connection/Connection.ts(194,40): error TS2322: Type 'SyncMessage<Action, unknown>' is not assignable to type 'SyncMessage<TeamAction, TeamContext>'.
@localfirst/auth:   Type 'Action' is not assignable to type 'TeamAction'.
@localfirst/auth:     Type '{ type: string; payload: any; }' is not assignable to type 'TeamAction'.
@localfirst/auth:       Type '{ type: string; payload: any; }' is not assignable to type 'RotateKeysAction'.
@localfirst/auth:         Types of property 'type' are incompatible.
@localfirst/auth:           Type 'string' is not assignable to type '"ROTATE_KEYS"'.
@localfirst/auth: [build] src/connection/Connection.ts(499,9): error TS2554: Expected 3 arguments, but got 4.
@localfirst/auth: [build] src/team/bySeniority.ts(12,44): error TS2769: No overload matches this call.
@localfirst/auth:   Overload 1 of 2, '(predicate: (this: void, value: unknown, index: number, obj: unknown[]) => value is unknown, thisArg?: any): unknown', gave the following error.
@localfirst/auth:     Argument of type '(link: TeamLink) => boolean' is not assignable to parameter of type '(this: void, value: unknown, index: number, obj: unknown[]) => value is unknown'.
@localfirst/auth:       Types of parameters 'link' and 'value' are incompatible.
@localfirst/auth:         Type 'unknown' is not assignable to type 'TeamLink'.
@localfirst/auth:           Type '{}' is missing the following properties from type 'Link<TeamAction, TeamContext>': hash, body, signed
@localfirst/auth:   Overload 2 of 2, '(predicate: (value: unknown, index: number, obj: unknown[]) => unknown, thisArg?: any): unknown', gave the following error.
@localfirst/auth:     Argument of type '(link: TeamLink) => boolean' is not assignable to parameter of type '(value: unknown, index: number, obj: unknown[]) => unknown'.
@localfirst/auth:       Types of parameters 'link' and 'value' are incompatible.
@localfirst/auth:         Type 'unknown' is not assignable to type 'TeamLink'.
@localfirst/auth:           Type 'unknown' is not assignable to type 'Link<TeamAction, TeamContext>'.
@localfirst/auth: [build] src/team/bySeniority.ts(17,28): error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'Link<Action, unknown>'.
@localfirst/auth:   Type '{}' is missing the following properties from type 'Link<Action, unknown>': hash, body, signed
@localfirst/auth: src/team/getMissingLinks.ts(1,18): error TS2305: Module '"crdx"' has no exported member 'HashGraph'.
@localfirst/auth: src/team/getMissingLinks.ts(5,27): error TS2339: Property 'body' does not exist on type 'unknown'.
@localfirst/auth: [build] src/team/membershipResolver.ts(144,57): error TS2551: Property 'userId' does not exist on type 'LinkBody<TeamAction, TeamContext>'. Did you mean 'user'?
@localfirst/auth:   Property 'userId' does not exist on type '{ user: User; timestamp: number; prev: string[]; } & RootAction & TeamContext'.
@localfirst/auth: [build] src/team/redactUser.ts(5,3): error TS2741: Property 'userId' is missing in type '{ roles: undefined[]; userName: string; keys: Keyset; }' but required in type 'Member'.
@localfirst/auth: [build] src/team/Team.ts(108,9): error TS2345: Argument of type '{ user: UserWithSecrets; reducer: Reducer<TeamState, TeamAction, TeamContext>; resolver: Resolver<TeamAction, TeamContext>; initialState: TeamState; rootPayload: { ...; }; graphKeys: KeysetWithSecrets; }' is not assignable to parameter of type 'StoreOptions<TeamState, TeamAction, TeamContext>'.
@localfirst/auth:   Object literal may only specify known properties, and 'graphKeys' does not exist in type 'StoreOptions<TeamState, TeamAction, TeamContext>'.
@localfirst/auth: src/team/Team.ts(121,9): error TS2345: Argument of type '{ user: UserWithSecrets; reducer: Reducer<TeamState, TeamAction, TeamContext>; resolver: Resolver<TeamAction, TeamContext>; initialState: TeamState; graph: any; graphKeys: KeysetWithSecrets; }' is not assignable to parameter of type 'StoreOptions<TeamState, TeamAction, TeamContext>'.
@localfirst/auth:   Object literal may only specify known properties, and 'graph' does not exist in type 'StoreOptions<TeamState, TeamAction, TeamContext>'.
@localfirst/auth: [build] src/team/Team.ts(152,23): error TS2339: Property 'getGraph' does not exist on type 'Store<TeamState, TeamAction, {}>'.
@localfirst/auth: src/team/Team.ts(625,7): error TS2345: Argument of type '{ user: UserWithSecrets; reducer: Reducer<TeamState, TeamAction, TeamContext>; resolver: Resolver<TeamAction, TeamContext>; initialState: TeamState; graph: any; graphKeys: KeysetWithSecrets; }' is not assignable to parameter of type 'StoreOptions<TeamState, TeamAction, TeamContext>'.
@localfirst/auth:   Object literal may only specify known properties, and 'graph' does not exist in type 'StoreOptions<TeamState, TeamAction, TeamContext>'.
@localfirst/auth: [build] src/team/Team.ts(740,53): error TS2339: Property 'userId' does not exist on type 'UserWithSecrets'.
@localfirst/auth: src/team/Team.ts(745,53): error TS2339: Property 'userId' does not exist on type 'UserWithSecrets'.
@localfirst/auth: src/team/Team.ts(800,52): error TS2554: Expected 1 arguments, but got 2.
@localfirst/auth: [build] src/team/types.ts(8,3): error TS2305: Module '"crdx"' has no exported member 'HashGraph'.
@localfirst/auth: src/team/validate.ts(30,19): error TS2339: Property 'userId' does not exist on type 'LinkBody<TeamAction, TeamContext>'.
@localfirst/auth: [build] src/team/validate.ts(65,32): error TS2551: Property 'userId' does not exist on type '{ user: User; timestamp: number; prev: string[]; } & ChangeMemberKeysAction & TeamContext'. Did you mean 'user'?
@localfirst/auth: src/util/testing/Network.ts(103,7): error TS2554: Expected 3 arguments, but got 4.
@localfirst/auth: [build] src/util/testing/setup.ts(42,41): error TS2554: Expected 1-2 arguments, but got 3.
@localfirst/auth: [build] [nodemon] app crashed - waiting for file changes before starting...

Sort out the choice of encryption key in crdx Store.dispatch

In crdx Store.dispatch, the you don't have to provide a graph key every time; if no key is provided, we use the same key that was used for the previous link. If the link has multiple parents, we choose the first one. This might be a source of undefined behavior though.

Make sure we have a plan for resolving seniority when two users were added concurrently

In the bySeniority sort function, we just check if a is a predecessor of b and if not, we assume that b is a predecessor of a. But they could have been added concurrently, in which case I'm not sure the current behavior is deterministic.

Test plan:

  • Two users are admitted concurrently.
  • They're both promoted to admins.
  • They try to remove each other concurrently.
  • Assert that everyone on the team resolves the conflict the same way

Check to see if this membership resolution error is still possible

This is from a comment in membershipResolver.test.ts:

sometimes (50% of the time?) when we eliminate duplicate ADD_MEMBERs,we're eliminating one that would have needed to have come BEFORE something else, in this case the CHANGE_MEMBER_KEYs action that happens after that person is admitted. Here's an example of a bad graph that you can end up with that way:

๐Ÿ‘ฉ๐Ÿพ ROOT
ADD_MEMBER:๐Ÿ‘จโ€๐Ÿฆฒ
                                                          <== ADD_MEMBER:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ was removed from here
INVITE:kPFx4gwGpuWplwa
INVITE:tiKXBLLdMbDndJE
ADMIT:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ
CHANGE_MEMBER_KEYS:{"type":"MEMBER","name":"๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ",...}    <== we can't do this because ๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ hasn't been added yet
ADD_DEVICE:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ:laptop
ADD_MEMBER:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ
INVITE:dQRE52A+7UGr8X9
ADD_MEMBER:๐Ÿ‘ด
INVITE:j6cC8ZyjyhuojZw
ADMIT:๐Ÿ‘ด
CHANGE_MEMBER_KEYS:{"type":"MEMBER","name":"๐Ÿ‘ด",...}
ADD_DEVICE:๐Ÿ‘ด:laptop

Here's how that graph should have been resolved:

๐Ÿ‘ฉ๐Ÿพ ROOT
ADD_MEMBER:๐Ÿ‘จโ€๐Ÿฆฒ
ADD_MEMBER:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ                                             <== in the bad graph,this ADD_MEMBER was discarded as a duplicate
INVITE:fNpSg0uBcW1vYvf
ADD_MEMBER:๐Ÿ‘ด
INVITE:PkD7SISvUt/3YlJ
ADMIT:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ
CHANGE_MEMBER_KEYS:{"type":"MEMBER","name":"๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ",...}
ADD_DEVICE:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ:laptop
                                                          <== ADD_MEMBER:๐Ÿ‘ณ๐Ÿฝโ€โ™‚๏ธ was removed from here
INVITE:Pu6NaY6HfbITAf6
INVITE:7vVS0NXz+u15Mx2
ADMIT:๐Ÿ‘ด
CHANGE_MEMBER_KEYS:{"type":"MEMBER","name":"๐Ÿ‘ด",...}
ADD_DEVICE:๐Ÿ‘ด:laptop

Separate graph keys from team keys

If we wanted to restrict a sync server's read access to application data (as opposed to the team membership data), we would currently have to create a new role that is only for human members (and ensure that every member was added to it), and encrypt the application data with that role's keys. It might make more sense to separate out the graph keys (for encrypting the team graph) from the team keys (for encrypting data for human members of the team).

Test plan:

  • Alice uses the team keys to encrypt a message
  • assert Bob and Charlie can decrypt the message
  • assert the server can't decrypt the message

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.