-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #687 from xmtp/rygine/frames-validator
Add `frames-validator` package
- Loading branch information
Showing
24 changed files
with
756 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# @xmtp/frames-validator | ||
|
||
## 0.6.2 | ||
|
||
### Patch Changes | ||
|
||
- [#260](https://github.com/xmtp/xmtp-node-js-tools/pull/260) [`57bf55d`](https://github.com/xmtp/xmtp-node-js-tools/commit/57bf55d89bce8a52a1dfaf8b7fc649054aaa6fd5) Thanks [@neekolas](https://github.com/neekolas)! - Update dependencies | ||
|
||
## 0.6.1 | ||
|
||
### Patch Changes | ||
|
||
- [#232](https://github.com/xmtp/xmtp-node-js-tools/pull/232) [`15c5032`](https://github.com/xmtp/xmtp-node-js-tools/commit/15c50320b06a80e50d666fa36da201cc754d3d68) Thanks [@daria-github](https://github.com/daria-github)! - Bumped version of proto package. | ||
|
||
## 0.6.0 | ||
|
||
### Minor Changes | ||
|
||
- [#191](https://github.com/xmtp/xmtp-node-js-tools/pull/191) [`da721b9`](https://github.com/xmtp/xmtp-node-js-tools/commit/da721b981ba7b225345c7086952f343592796992) Thanks [@alexrisch](https://github.com/alexrisch)! - Added State handling | ||
|
||
## 0.5.2 | ||
|
||
### Patch Changes | ||
|
||
- [#169](https://github.com/xmtp/xmtp-node-js-tools/pull/169) [`ea52fb6`](https://github.com/xmtp/xmtp-node-js-tools/commit/ea52fb63562d611307c7005c8fba472bc286e7e7) Thanks [@neekolas](https://github.com/neekolas)! - Add state field | ||
|
||
## 0.5.1 | ||
|
||
### Patch Changes | ||
|
||
- [#161](https://github.com/xmtp/xmtp-node-js-tools/pull/161) [`0c3cbb8`](https://github.com/xmtp/xmtp-node-js-tools/commit/0c3cbb8fb3aa392ec72787e1512d177c7c49a011) Thanks [@neekolas](https://github.com/neekolas)! - Upgrade xmtp proto | ||
|
||
## 0.5.0 | ||
|
||
### Minor Changes | ||
|
||
- [#154](https://github.com/xmtp/xmtp-node-js-tools/pull/154) [`7530777`](https://github.com/xmtp/xmtp-node-js-tools/commit/7530777be8e863a87bc5cad6136db8202eb9bea7) Thanks [@neekolas](https://github.com/neekolas)! - Switch out encryption library for better commonjs support | ||
|
||
## 0.4.0 | ||
|
||
### Minor Changes | ||
|
||
- [#147](https://github.com/xmtp/xmtp-node-js-tools/pull/147) [`9ad92d8`](https://github.com/xmtp/xmtp-node-js-tools/commit/9ad92d801ce58a0610078016640a4e611b73e662) Thanks [@neekolas](https://github.com/neekolas)! - Adds support for an Open Frames validator | ||
|
||
## 0.3.1 | ||
|
||
### Patch Changes | ||
|
||
- [#145](https://github.com/xmtp/xmtp-node-js-tools/pull/145) [`5fb6232`](https://github.com/xmtp/xmtp-node-js-tools/commit/5fb623267505a3e964281e3527c76c6a1c752c14) Thanks [@neekolas](https://github.com/neekolas)! - Export all the types | ||
|
||
## 0.3.0 | ||
|
||
### Minor Changes | ||
|
||
- [#143](https://github.com/xmtp/xmtp-node-js-tools/pull/143) [`050c529`](https://github.com/xmtp/xmtp-node-js-tools/commit/050c52986414773dba01796ed86d1ea5ec365be8) Thanks [@neekolas](https://github.com/neekolas)! - Configure to export for both Node.js and ESM | ||
|
||
## 0.2.0 | ||
|
||
### Minor Changes | ||
|
||
- [#140](https://github.com/xmtp/xmtp-node-js-tools/pull/140) [`4010423`](https://github.com/xmtp/xmtp-node-js-tools/commit/40104235bb8f5ab62cd98e35214d62e268816c93) Thanks [@neekolas](https://github.com/neekolas)! - Update to latest version of our protos | ||
|
||
## 0.1.1 | ||
|
||
### Patch Changes | ||
|
||
- [#133](https://github.com/xmtp/xmtp-node-js-tools/pull/133) [`ee73b40`](https://github.com/xmtp/xmtp-node-js-tools/commit/ee73b40f72f22d62bd3d341ce691cc30e18c3ec3) Thanks [@neekolas](https://github.com/neekolas)! - Fix import error | ||
|
||
## 0.1.0 | ||
|
||
### Minor Changes | ||
|
||
- [#131](https://github.com/xmtp/xmtp-node-js-tools/pull/131) [`03a6083`](https://github.com/xmtp/xmtp-node-js-tools/commit/03a608352ec9814edda449ad75610a78ad6c4110) Thanks [@neekolas](https://github.com/neekolas)! - Initialize frames-validator package |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Frames Validator | ||
|
||
A set of tools for validating POST payloads from XMTP Frames | ||
|
||
## Usage | ||
|
||
```ts | ||
import { validateFramesPost } from "@xmtp/frames-validator" | ||
|
||
export function handler(requestBody: any) { | ||
// This is an XMTP payload | ||
if (requestBody.untrustedData?.clientType === "xmtp") { | ||
const { verifiedWalletAddress } = await validateFramesPost(requestBody) | ||
return doSomethingWithWalletAddress(verifiedWalletAddress) | ||
} else { | ||
// This is a Farcaster POST payload | ||
return doSomethingWithFarcasterPayload(requestBody) | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
{ | ||
"name": "@xmtp/frames-validator", | ||
"version": "0.6.2", | ||
"description": "A validator for XMTP frames requests", | ||
"homepage": "https://github.com/xmtp/xmtp-node-js-tools#readme", | ||
"bugs": { | ||
"url": "https://github.com/xmtp/xmtp-node-js-tools/issues" | ||
}, | ||
"license": "MIT", | ||
"author": "XMTP Labs <[email protected]>", | ||
"type": "module", | ||
"exports": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.js", | ||
"require": "./dist/index.cjs" | ||
} | ||
}, | ||
"main": "dist/index.cjs", | ||
"module": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "yarn clean:dist && yarn rollup -c", | ||
"clean": "rm -rf .turbo && rm -rf node_modules && yarn clean:dist", | ||
"clean:dist": "rm -rf dist", | ||
"test": "vitest run", | ||
"typecheck": "tsc" | ||
}, | ||
"dependencies": { | ||
"@noble/curves": "^1.3.0", | ||
"@noble/hashes": "^1.4.0", | ||
"@xmtp/proto": "3.61.1", | ||
"viem": "^2.16.5" | ||
}, | ||
"devDependencies": { | ||
"@open-frames/types": "^0.1.1", | ||
"@rollup/plugin-typescript": "^12.1.1", | ||
"@xmtp/frames-client": "^0.5.4", | ||
"@xmtp/xmtp-js": "^12.1.0", | ||
"ethers": "^6.10.0", | ||
"rollup": "^4.24.0", | ||
"rollup-plugin-dts": "^6.1.1", | ||
"typescript": "^5.6.3", | ||
"vitest": "^2.1.3" | ||
}, | ||
"packageManager": "[email protected]", | ||
"engines": { | ||
"node": ">=20" | ||
}, | ||
"publishConfig": { | ||
"access": "public", | ||
"provenance": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import typescript from "@rollup/plugin-typescript"; | ||
import { defineConfig } from "rollup"; | ||
import { dts } from "rollup-plugin-dts"; | ||
|
||
const external = [ | ||
"@noble/curves/abstract/utils", | ||
"@noble/curves/secp256k1", | ||
"@noble/hashes/sha256", | ||
"@xmtp/proto", | ||
"viem/utils", | ||
]; | ||
|
||
const plugins = [ | ||
typescript({ | ||
declaration: false, | ||
declarationMap: false, | ||
}), | ||
]; | ||
|
||
export default defineConfig([ | ||
{ | ||
input: "src/index.ts", | ||
output: { | ||
file: "dist/index.js", | ||
format: "es", | ||
sourcemap: true, | ||
}, | ||
plugins, | ||
external, | ||
}, | ||
{ | ||
input: "src/index.ts", | ||
output: { | ||
file: "dist/index.cjs", | ||
format: "cjs", | ||
sourcemap: true, | ||
}, | ||
plugins, | ||
external, | ||
}, | ||
{ | ||
input: "src/index.ts", | ||
output: { | ||
file: "dist/index.d.ts", | ||
format: "es", | ||
}, | ||
plugins: [dts()], | ||
}, | ||
]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { FramesClient } from "@xmtp/frames-client"; | ||
import { fetcher, frames } from "@xmtp/proto"; | ||
import { Client, PrivateKeyBundleV2 } from "@xmtp/xmtp-js"; | ||
import { Wallet } from "ethers"; | ||
import { beforeEach, describe, expect, it } from "vitest"; | ||
import { deserializeProtoMessage, validateFramesPost } from "."; | ||
|
||
const { b64Decode, b64Encode } = fetcher; | ||
|
||
function scrambleBytes(bytes: Uint8Array) { | ||
const scrambled = new Uint8Array(bytes.length); | ||
for (let i = 0; i < bytes.length; i++) { | ||
scrambled[i] = bytes[bytes.length - i - 1]; | ||
} | ||
return scrambled; | ||
} | ||
|
||
describe("validations", () => { | ||
let client: Client; | ||
let framesClient: FramesClient; | ||
|
||
const FRAME_URL = "https://frame.xyz"; | ||
const CONVERSATION_TOPIC = "/xmtp/0/1234"; | ||
const PARTICIPANT_ACCOUNT_ADDRESSES = ["0x1234", "0x5678"]; | ||
const BUTTON_INDEX = 2; | ||
|
||
beforeEach(async () => { | ||
const wallet = Wallet.createRandom(); | ||
client = await Client.create(wallet); | ||
framesClient = new FramesClient(client); | ||
}); | ||
|
||
it("succeeds in the happy path", async () => { | ||
const postData = await framesClient.signFrameAction({ | ||
buttonIndex: BUTTON_INDEX, | ||
frameUrl: FRAME_URL, | ||
conversationTopic: CONVERSATION_TOPIC, | ||
participantAccountAddresses: PARTICIPANT_ACCOUNT_ADDRESSES, | ||
}); | ||
const validated = validateFramesPost(postData); | ||
expect(validated.verifiedWalletAddress).toEqual(client.address); | ||
}); | ||
|
||
it("fails if the signature verification fails", async () => { | ||
const postData = await framesClient.signFrameAction({ | ||
buttonIndex: BUTTON_INDEX, | ||
frameUrl: FRAME_URL, | ||
conversationTopic: CONVERSATION_TOPIC, | ||
participantAccountAddresses: PARTICIPANT_ACCOUNT_ADDRESSES, | ||
}); | ||
// Monkey around with the signature | ||
const deserialized = deserializeProtoMessage( | ||
b64Decode(postData.trustedData.messageBytes), | ||
); | ||
|
||
if (!deserialized.signature.ecdsaCompact?.bytes) { | ||
throw new Error("Signature bytes are empty"); | ||
} | ||
|
||
deserialized.signature.ecdsaCompact.bytes = scrambleBytes( | ||
deserialized.signature.ecdsaCompact.bytes, | ||
); | ||
const reserialized = frames.FrameAction.encode({ | ||
signature: deserialized.signature, | ||
actionBody: deserialized.actionBodyBytes, | ||
signedPublicKeyBundle: deserialized.signedPublicKeyBundle, | ||
}).finish(); | ||
|
||
postData.trustedData.messageBytes = b64Encode( | ||
reserialized, | ||
0, | ||
reserialized.length, | ||
); | ||
|
||
expect(() => validateFramesPost(postData)).toThrow(); | ||
}); | ||
|
||
it("fails if the wallet address doesn't match", async () => { | ||
const postData = await framesClient.signFrameAction({ | ||
buttonIndex: BUTTON_INDEX, | ||
frameUrl: FRAME_URL, | ||
conversationTopic: CONVERSATION_TOPIC, | ||
participantAccountAddresses: PARTICIPANT_ACCOUNT_ADDRESSES, | ||
}); | ||
// Monkey around with the signature | ||
const deserialized = deserializeProtoMessage( | ||
b64Decode(postData.trustedData.messageBytes), | ||
); | ||
|
||
const throwAwayWallet = Wallet.createRandom(); | ||
const wrongPublicKeyBundle = ( | ||
await PrivateKeyBundleV2.generate(throwAwayWallet) | ||
).getPublicKeyBundle(); | ||
|
||
const reserialized = frames.FrameAction.encode({ | ||
signature: deserialized.signature, | ||
actionBody: deserialized.actionBodyBytes, | ||
signedPublicKeyBundle: wrongPublicKeyBundle, | ||
}).finish(); | ||
|
||
postData.trustedData.messageBytes = b64Encode( | ||
reserialized, | ||
0, | ||
reserialized.length, | ||
); | ||
|
||
expect(() => validateFramesPost(postData)).toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./openFrames.js"; | ||
export * from "./validation.js"; |
Oops, something went wrong.