-
Notifications
You must be signed in to change notification settings - Fork 8
verify space events identities #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,10 @@ import { Effect, Exit } from 'effect'; | |
|
||
import type { Messages } from '@graphprotocol/hypergraph'; | ||
|
||
import { SpaceEvents } from '@graphprotocol/hypergraph'; | ||
import { Identity, SpaceEvents } from '@graphprotocol/hypergraph'; | ||
|
||
import { prisma } from '../prisma.js'; | ||
import { getIdentity } from './getIdentity.js'; | ||
|
||
type Params = { | ||
accountId: string; | ||
|
@@ -14,7 +15,22 @@ type Params = { | |
}; | ||
|
||
export const createSpace = async ({ accountId, event, keyBox, keyId }: Params) => { | ||
const result = await Effect.runPromiseExit(SpaceEvents.applyEvent({ event, state: undefined })); | ||
const getVerifiedIdentity = (accountIdToFetch: string) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I see there's a few repetitions of this so maybe they could be split out into a utility function like this (in a separate file):
Then you can pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good, will do it in a follow up PR 👍 |
||
// applySpaceEvent is only allowed to be called by the account that is applying the event | ||
if (accountIdToFetch !== accountId) { | ||
return Effect.fail(new Identity.InvalidIdentityError()); | ||
} | ||
|
||
return Effect.gen(function* () { | ||
const identity = yield* Effect.tryPromise({ | ||
try: () => getIdentity({ accountId: accountIdToFetch }), | ||
catch: () => new Identity.InvalidIdentityError(), | ||
}); | ||
return identity; | ||
}); | ||
}; | ||
|
||
const result = await Effect.runPromiseExit(SpaceEvents.applyEvent({ event, state: undefined, getVerifiedIdentity })); | ||
if (Exit.isFailure(result)) { | ||
throw new Error('Invalid event'); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import * as Schema from 'effect/Schema'; | ||
import * as Messages from '../messages/index.js'; | ||
import { store } from '../store.js'; | ||
import { verifyIdentityOwnership } from './prove-ownership.js'; | ||
|
||
export const getVerifiedIdentity = async ( | ||
accountId: string, | ||
syncServerUri: string, | ||
): Promise<{ | ||
accountId: string; | ||
encryptionPublicKey: string; | ||
signaturePublicKey: string; | ||
}> => { | ||
const storeState = store.getSnapshot(); | ||
const identity = storeState.context.identities[accountId]; | ||
if (identity) { | ||
return { | ||
accountId, | ||
encryptionPublicKey: identity.encryptionPublicKey, | ||
signaturePublicKey: identity.signaturePublicKey, | ||
}; | ||
} | ||
const res = await fetch(`${syncServerUri}/identity?accountId=${accountId}`); | ||
if (res.status !== 200) { | ||
throw new Error('Failed to fetch identity'); | ||
} | ||
const resDecoded = Schema.decodeUnknownSync(Messages.ResponseIdentity)(await res.json()); | ||
|
||
if ( | ||
!(await verifyIdentityOwnership( | ||
resDecoded.accountId, | ||
resDecoded.signaturePublicKey, | ||
resDecoded.accountProof, | ||
resDecoded.keyProof, | ||
)) | ||
) { | ||
throw new Error('Invalid identity'); | ||
} | ||
|
||
store.send({ | ||
type: 'addVerifiedIdentity', | ||
accountId: resDecoded.accountId, | ||
encryptionPublicKey: resDecoded.encryptionPublicKey, | ||
signaturePublicKey: resDecoded.signaturePublicKey, | ||
accountProof: resDecoded.accountProof, | ||
keyProof: resDecoded.keyProof, | ||
}); | ||
return { | ||
accountId: resDecoded.accountId, | ||
encryptionPublicKey: resDecoded.encryptionPublicKey, | ||
signaturePublicKey: resDecoded.signaturePublicKey, | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess technically we could remove this check, right? It's assuming the behavior of applySpaceEvent, in the future we could have a case where we need to check the identity for a different account mentioned in the event. (That being said I think it's okay to leave this as it is and change it in the future if needed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you are right that technically we could remove this check.
At the moment this ensures that the server only applies an event created that this account created. This must not be enforced, but I sleep a bit better that we enforce it. At least until we explicitly only allow accounts to send events to a sync server they themselves created