From 534ec58ce019c51452966c0a5e0a10d436e63f8b Mon Sep 17 00:00:00 2001
From: Ry Racherbaumer <ry@xmtp.com>
Date: Fri, 22 Nov 2024 17:44:14 -0600
Subject: [PATCH] Refactor signature verification

---
 sdks/node-sdk/package.json        |  1 +
 sdks/node-sdk/src/Client.ts       | 31 +++++++++++++++++---------
 sdks/node-sdk/test/Client.test.ts | 36 +++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/sdks/node-sdk/package.json b/sdks/node-sdk/package.json
index ce6b39156..7e3fce5c3 100644
--- a/sdks/node-sdk/package.json
+++ b/sdks/node-sdk/package.json
@@ -69,6 +69,7 @@
     "rollup-plugin-filesize": "^10.0.0",
     "rollup-plugin-tsconfig-paths": "^1.5.2",
     "typescript": "^5.6.3",
+    "uint8array-extras": "^1.4.0",
     "uuid": "^11.0.3",
     "viem": "^2.13.6",
     "vite": "^5.4.11",
diff --git a/sdks/node-sdk/src/Client.ts b/sdks/node-sdk/src/Client.ts
index 05550b6cf..2bd7eff06 100644
--- a/sdks/node-sdk/src/Client.ts
+++ b/sdks/node-sdk/src/Client.ts
@@ -17,6 +17,7 @@ import {
   GroupMessageKind,
   LogLevel,
   SignatureRequestType,
+  verifySignedWithPublicKey as verifySignedWithPublicKeyBinding,
   type Consent,
   type ConsentEntityType,
   type LogOptions,
@@ -410,21 +411,31 @@ export class Client {
     signatureText: string,
     signatureBytes: Uint8Array,
   ) {
-    this.#innerClient.verifySignedWithInstallationKey(
-      signatureText,
-      signatureBytes,
-    );
+    try {
+      this.#innerClient.verifySignedWithInstallationKey(
+        signatureText,
+        signatureBytes,
+      );
+      return true;
+    } catch {
+      return false;
+    }
   }
 
-  verifySignedWithPublicKey(
+  static verifySignedWithPublicKey(
     signatureText: string,
     signatureBytes: Uint8Array,
     publicKey: Uint8Array,
   ) {
-    this.#innerClient.verifySignedWithPublicKey(
-      signatureText,
-      signatureBytes,
-      publicKey,
-    );
+    try {
+      verifySignedWithPublicKeyBinding(
+        signatureText,
+        signatureBytes,
+        publicKey,
+      );
+      return true;
+    } catch {
+      return false;
+    }
   }
 }
diff --git a/sdks/node-sdk/test/Client.test.ts b/sdks/node-sdk/test/Client.test.ts
index 5beff1d26..59e742f24 100644
--- a/sdks/node-sdk/test/Client.test.ts
+++ b/sdks/node-sdk/test/Client.test.ts
@@ -1,4 +1,5 @@
 import { ConsentEntityType, ConsentState } from "@xmtp/node-bindings";
+import { uint8ArrayToHex } from "uint8array-extras";
 import { v4 } from "uuid";
 import { describe, expect, it } from "vitest";
 import { Client } from "@/Client";
@@ -195,4 +196,39 @@ describe("Client", () => {
       await client2.getConsentState(ConsentEntityType.GroupId, group2!.id),
     ).toBe(ConsentState.Denied);
   });
+
+  it("should verify signatures", async () => {
+    const user = createUser();
+    const client = await createRegisteredClient(user);
+    const signatureText = "gm1";
+    const signature = client.signWithInstallationKey(signatureText);
+    const verified = client.verifySignedWithInstallationKey(
+      signatureText,
+      signature,
+    );
+    expect(verified).toBe(true);
+    const verified2 = Client.verifySignedWithPublicKey(
+      signatureText,
+      signature,
+      client.installationIdBytes,
+    );
+    expect(verified2).toBe(true);
+
+    const signatureText2 = new Uint8Array(32).fill(1);
+    const signature2 = client.signWithInstallationKey(
+      uint8ArrayToHex(signatureText2),
+    );
+    const verified3 = Client.verifySignedWithPublicKey(
+      uint8ArrayToHex(signatureText2),
+      signature2,
+      client.installationIdBytes,
+    );
+    expect(verified3).toBe(true);
+    const verified4 = Client.verifySignedWithPublicKey(
+      uint8ArrayToHex(signatureText2),
+      signature,
+      client.installationIdBytes,
+    );
+    expect(verified4).toBe(false);
+  });
 });