Skip to content
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

Add frames-validator package #687

Merged
merged 51 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d2d6358
Create frames validator
neekolas Jan 30, 2024
f96f95b
Change version
neekolas Jan 30, 2024
5db7c90
RELEASING: Releasing 1 package(s)
github-actions[bot] Jan 30, 2024
70591f9
Fix import bug
neekolas Jan 30, 2024
84f4a04
RELEASING: Releasing 1 package(s)
github-actions[bot] Jan 30, 2024
aae4289
Use latest version
neekolas Feb 6, 2024
41c107e
Upgrade typescript
neekolas Feb 6, 2024
e913cc1
RELEASING: Releasing 1 package(s)
github-actions[bot] Feb 6, 2024
6f51199
Configure to support .cjs and esm exports
neekolas Feb 7, 2024
645b75d
Add README
neekolas Feb 7, 2024
44ba64d
Keep as module
rygine Feb 7, 2024
ec1a4a8
RELEASING: Releasing 1 package(s)
github-actions[bot] Feb 7, 2024
3029db9
Export all the types
neekolas Feb 7, 2024
05abd59
RELEASING: Releasing 1 package(s)
github-actions[bot] Feb 7, 2024
3bb8bf9
Add OpenFrames support
neekolas Feb 10, 2024
4d4d6de
Update types version
neekolas Feb 10, 2024
6270172
Remove xmtp-js dep
neekolas Feb 13, 2024
ec03d36
Run yarn
neekolas Feb 13, 2024
a9b956e
RELEASING: Releasing 1 package(s)
github-actions[bot] Feb 14, 2024
c458e36
Use noble curves
neekolas Feb 16, 2024
431efb2
Remove unused await
neekolas Feb 16, 2024
03c651e
Update lock file
neekolas Feb 16, 2024
9058d90
RELEASING: Releasing 1 package(s)
github-actions[bot] Feb 16, 2024
cd72794
Upgrade xmtp proto
neekolas Feb 23, 2024
d16d7f5
RELEASING: Releasing 1 package(s)
github-actions[bot] Feb 23, 2024
1bb9f18
build(deps): Bump @xmtp/xmtp-js from 11.3.5 to 11.3.12
dependabot[bot] Feb 23, 2024
732b0a7
build(deps-dev): Bump rollup from 4.9.6 to 4.12.0
dependabot[bot] Feb 23, 2024
3ee0b62
build(deps): Bump viem from 2.7.8 to 2.7.14
dependabot[bot] Feb 26, 2024
7914099
Add State field to be in line with of spec
neekolas Feb 29, 2024
8243d33
RELEASING: Releasing 1 package(s)
github-actions[bot] Mar 1, 2024
6876010
build(deps): Bump @noble/hashes from 1.3.3 to 1.4.0
dependabot[bot] Mar 18, 2024
5e2f624
build(deps-dev): Bump rollup from 4.12.0 to 4.13.0
dependabot[bot] Mar 25, 2024
3c12886
Update packages
Mar 28, 2024
d6f44d3
feat: Check untrusted data
Mar 28, 2024
ce681fb
RELEASING: Releasing 1 package(s)
github-actions[bot] Apr 3, 2024
14834ba
build(deps): Bump @xmtp/proto from 3.45.0 to 3.52.0
dependabot[bot] Apr 22, 2024
99ed2e0
build(deps): Bump viem from 2.7.14 to 2.9.28
dependabot[bot] Apr 29, 2024
f542d8d
build(deps): Bump @xmtp/proto from 3.52.0 to 3.56.0
dependabot[bot] May 6, 2024
27a01c6
build(deps-dev): Bump typescript from 5.3.3 to 5.4.5
dependabot[bot] May 6, 2024
09fe63b
RELEASING: Releasing 1 package(s)
github-actions[bot] May 21, 2024
8d7d2ca
build(deps): Bump @xmtp/proto from 3.56.0 to 3.61.1
dependabot[bot] May 27, 2024
9b43eef
build(deps): Bump viem from 2.9.28 to 2.16.5
dependabot[bot] Jul 1, 2024
f86e0d5
build(deps-dev): Bump rollup-plugin-dts from 6.1.0 to 6.1.1
dependabot[bot] May 30, 2024
8e672ee
RELEASING: Releasing 1 package(s)
github-actions[bot] Jul 3, 2024
e06f8c7
Update tsconfig
rygine Oct 17, 2024
a02f978
Run prettier
rygine Oct 17, 2024
8343163
Update dev deps
rygine Oct 17, 2024
b5df2c2
Fix up package.json and configs
rygine Oct 18, 2024
e6f2fdc
Fix lint issues
rygine Oct 18, 2024
4008b4c
Update yarn.lock
rygine Oct 18, 2024
f6c756b
Fix turbo config
rygine Oct 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content-types/content-type-primitives/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"happy-dom": "^15.7.4",
"rimraf": "^6.0.1",
"rollup": "^4.24.0",
Expand Down
2 changes: 1 addition & 1 deletion content-types/content-type-reaction/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"@xmtp/xmtp-js": "^11.6.3",
"buffer": "^6.0.3",
"ethers": "^6.11.1",
Expand Down
2 changes: 1 addition & 1 deletion content-types/content-type-read-receipt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"@xmtp/xmtp-js": "^11.6.3",
"buffer": "^6.0.3",
"ethers": "^6.11.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"@xmtp/rollup-plugin-resolve-extensions": "^1.0.1",
"@xmtp/xmtp-js": "^11.6.3",
"buffer": "^6.0.3",
Expand Down
2 changes: 1 addition & 1 deletion content-types/content-type-reply/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"@xmtp/content-type-remote-attachment": "workspace:*",
"@xmtp/xmtp-js": "^11.6.3",
"buffer": "^6.0.3",
Expand Down
2 changes: 1 addition & 1 deletion content-types/content-type-text/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"@xmtp/xmtp-js": "^11.6.3",
"buffer": "^6.0.3",
"ethers": "^6.11.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"@xmtp/xmtp-js": "^11.6.3",
"buffer": "^6.0.3",
"ethers": "^6.11.1",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@eslint/js": "^9.12.0",
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@types/eslint__js": "^8.42.3",
"@types/node": "^20.16.11",
"@types/node": "^20.16.12",
"eslint": "^9.12.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
Expand Down
73 changes: 73 additions & 0 deletions packages/frames-validator/CHANGELOG.md
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
20 changes: 20 additions & 0 deletions packages/frames-validator/README.md
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)
}
}
```
57 changes: 57 additions & 0 deletions packages/frames-validator/package.json
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
}
}
49 changes: 49 additions & 0 deletions packages/frames-validator/rollup.config.js
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()],
},
]);
109 changes: 109 additions & 0 deletions packages/frames-validator/src/index.test.ts
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();
});
});
2 changes: 2 additions & 0 deletions packages/frames-validator/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./openFrames.js";
export * from "./validation.js";
Loading
Loading