From 697fbc9b6b9a2750610e3976b1030595dc60bf7d Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Sat, 29 Oct 2022 20:32:10 +0200 Subject: [PATCH 1/8] add webhook sign --- src/sign/index.ts | 32 +++++++++++++++++++++++++++++++- src/sign/types.ts | 17 +++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/sign/index.ts b/src/sign/index.ts index 96e585ff0..38c93caa3 100644 --- a/src/sign/index.ts +++ b/src/sign/index.ts @@ -10,6 +10,7 @@ import { Unfollow, Subscribe, Unsubscribe, + AddWebhook, Profile, Alias, spaceTypes, @@ -26,12 +27,14 @@ import { subscribeTypes, unfollowTypes, unsubscribeTypes, + addWebhookTypes, profileTypes, aliasTypes, deleteSpaceType, DeleteSpace } from './types'; import hubs from '../hubs.json'; +import { verify } from './utils'; const NAME = 'snapshot'; const VERSION = '0.1.4'; @@ -49,7 +52,13 @@ export default class Client { this.address = address; } - async sign(web3: Web3Provider | Wallet, address: string, message, types) { + async sign( + web3: Web3Provider | Wallet, + address: string, + message, + types, + skipHub?: boolean + ) { // @ts-ignore const signer = web3?.getSigner ? web3.getSigner() : web3; if (!message.from) message.from = address; @@ -58,6 +67,19 @@ export default class Client { const data: any = { domain, types, message }; const sig = await signer._signTypedData(domain, data.types, message); // console.log('Sign', { address, sig, data }); + if (skipHub) { + try { + const isValidSig = await verify(address, sig, data); + if (!isValidSig) return Promise.reject('wrong signature'); + + return true; + } catch (e) { + console.warn(`signature validation failed for ${address}`); + + return Promise.reject('signature validation failed'); + } + } + return await this.send({ address, sig, data }); } @@ -155,6 +177,14 @@ export default class Client { return await this.sign(web3, address, message, unsubscribeTypes); } + async webhook( + web3: Web3Provider | Wallet, + address: string, + message: AddWebhook + ) { + return await this.sign(web3, address, message, addWebhookTypes, true); + } + async profile( web3: Web3Provider | Wallet, address: string, diff --git a/src/sign/types.ts b/src/sign/types.ts index 2c954c27e..e41b5661c 100644 --- a/src/sign/types.ts +++ b/src/sign/types.ts @@ -72,6 +72,14 @@ export interface Unsubscribe { timestamp?: number; } +export interface AddWebhook { + from?: string; + space: string; + url: string; + active: number; + timestamp?: number; +} + export interface Profile { from?: string; timestamp?: number; @@ -235,6 +243,15 @@ export const unsubscribeTypes = { ] }; +export const addWebhookTypes = { + Webhook: [ + { name: 'from', type: 'address' }, + { name: 'space', type: 'string' }, + { name: 'url', type: 'string' }, + { name: 'active', type: 'uint8' } + ] +}; + export const profileTypes = { Profile: [ { name: 'from', type: 'address' }, From 6fd01988c0b0b7abbb54b15a6410670e47581f77 Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Sun, 30 Oct 2022 17:15:40 +0100 Subject: [PATCH 2/8] add removewebhook action --- package.json | 1 + src/sign/index.ts | 53 +++++++++++++++++++++++------------------------ src/sign/types.ts | 17 ++++++++++++++- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index c8e78c016..6e415fc52 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@ethersproject/hash": "^5.6.1", "@ethersproject/providers": "^5.6.8", "@ethersproject/wallet": "^5.6.2", + "@snapshot-labs/snapshot.js": "^0.4.43", "ajv": "^8.11.0", "ajv-formats": "^2.1.1", "cross-fetch": "^3.1.5", diff --git a/src/sign/index.ts b/src/sign/index.ts index 38c93caa3..105b62421 100644 --- a/src/sign/index.ts +++ b/src/sign/index.ts @@ -10,7 +10,8 @@ import { Unfollow, Subscribe, Unsubscribe, - AddWebhook, + Webhook, + RemoveWebhook, Profile, Alias, spaceTypes, @@ -28,6 +29,7 @@ import { unfollowTypes, unsubscribeTypes, addWebhookTypes, + removeWebhookTypes, profileTypes, aliasTypes, deleteSpaceType, @@ -46,45 +48,34 @@ export const domain = { }; export default class Client { - readonly address: string; + readonly hubAddress: string; + readonly webhookAddress: string; constructor(address: string = hubs[0]) { - this.address = address; + this.hubAddress = address; + this.webhookAddress = 'http://localhost:3000'; } - async sign( - web3: Web3Provider | Wallet, - address: string, - message, - types, - skipHub?: boolean - ) { + async sign(web3: Web3Provider | Wallet, address: string, message, types) { // @ts-ignore const signer = web3?.getSigner ? web3.getSigner() : web3; if (!message.from) message.from = address; if (!message.timestamp) - message.timestamp = parseInt((Date.now() / 1e3).toFixed()); + message.timestamp = parseInt((Date.now() / 1e3).toFixed()); const data: any = { domain, types, message }; const sig = await signer._signTypedData(domain, data.types, message); - // console.log('Sign', { address, sig, data }); - if (skipHub) { - try { - const isValidSig = await verify(address, sig, data); - if (!isValidSig) return Promise.reject('wrong signature'); - - return true; - } catch (e) { - console.warn(`signature validation failed for ${address}`); - - return Promise.reject('signature validation failed'); - } - } + console.log('Sign', { address, sig, data }); return await this.send({ address, sig, data }); } async send(envelop) { - const url = `${this.address}/api/msg`; + const webhookAction = Object.keys(envelop.data.types).filter(key => ['Webhook', 'RemoveWebhook'].includes(key)).length + console.log('webhook', webhookAction); + const url = + webhookAction > 0 + ? `${this.webhookAddress}/api/subscribers` + : `${this.hubAddress}/api/msg`; const init = { method: 'POST', headers: { @@ -180,9 +171,17 @@ export default class Client { async webhook( web3: Web3Provider | Wallet, address: string, - message: AddWebhook + message: Webhook + ) { + return await this.sign(web3, address, message, addWebhookTypes); + } + + async removeWebhook( + web3: Web3Provider | Wallet, + address: string, + message: RemoveWebhook ) { - return await this.sign(web3, address, message, addWebhookTypes, true); + return await this.sign(web3, address, message, removeWebhookTypes); } async profile( diff --git a/src/sign/types.ts b/src/sign/types.ts index e41b5661c..4c4131b55 100644 --- a/src/sign/types.ts +++ b/src/sign/types.ts @@ -72,7 +72,7 @@ export interface Unsubscribe { timestamp?: number; } -export interface AddWebhook { +export interface Webhook { from?: string; space: string; url: string; @@ -80,6 +80,13 @@ export interface AddWebhook { timestamp?: number; } +export interface RemoveWebhook { + from?: string; + id: number; + active: number; + timestamp?: number; +} + export interface Profile { from?: string; timestamp?: number; @@ -252,6 +259,14 @@ export const addWebhookTypes = { ] }; +export const removeWebhookTypes = { + RemoveWebhook: [ + { name: 'from', type: 'address' }, + { name: 'id', type: 'uint64' }, + { name: 'active', type: 'uint8' } + ] +}; + export const profileTypes = { Profile: [ { name: 'from', type: 'address' }, From 9f274944d4284c82b9c67eb9042463088d13338c Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Mon, 31 Oct 2022 17:22:28 +0100 Subject: [PATCH 3/8] update webhook type name --- src/schemas/webhook.json | 26 ++++++++++++++++++++++++++ src/sign/index.ts | 6 ++---- src/sign/types.ts | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/schemas/webhook.json diff --git a/src/schemas/webhook.json b/src/schemas/webhook.json new file mode 100644 index 000000000..3bcda6e14 --- /dev/null +++ b/src/schemas/webhook.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Webhook", + "definitions": { + "Webhook": { + "title": "Webhook", + "type": "object", + "properties": { + "space": { + "type": "string", + "title": "space" + }, + "url": { + "type": "string", + "title": "url", + "format": "url" + } + }, + "required": [ + "space", + "url" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/src/sign/index.ts b/src/sign/index.ts index 105b62421..cd5c8ebdc 100644 --- a/src/sign/index.ts +++ b/src/sign/index.ts @@ -28,7 +28,7 @@ import { subscribeTypes, unfollowTypes, unsubscribeTypes, - addWebhookTypes, + webhookTypes, removeWebhookTypes, profileTypes, aliasTypes, @@ -36,7 +36,6 @@ import { DeleteSpace } from './types'; import hubs from '../hubs.json'; -import { verify } from './utils'; const NAME = 'snapshot'; const VERSION = '0.1.4'; @@ -71,7 +70,6 @@ export default class Client { async send(envelop) { const webhookAction = Object.keys(envelop.data.types).filter(key => ['Webhook', 'RemoveWebhook'].includes(key)).length - console.log('webhook', webhookAction); const url = webhookAction > 0 ? `${this.webhookAddress}/api/subscribers` @@ -173,7 +171,7 @@ export default class Client { address: string, message: Webhook ) { - return await this.sign(web3, address, message, addWebhookTypes); + return await this.sign(web3, address, message, webhookTypes); } async removeWebhook( diff --git a/src/sign/types.ts b/src/sign/types.ts index 4c4131b55..4d6efab05 100644 --- a/src/sign/types.ts +++ b/src/sign/types.ts @@ -250,7 +250,7 @@ export const unsubscribeTypes = { ] }; -export const addWebhookTypes = { +export const webhookTypes = { Webhook: [ { name: 'from', type: 'address' }, { name: 'space', type: 'string' }, From 34a5a5ff6e8e3e3a0e44fe35bbf5e8bce4b091b3 Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Mon, 31 Oct 2022 17:23:04 +0100 Subject: [PATCH 4/8] comment out console.log --- src/sign/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sign/index.ts b/src/sign/index.ts index cd5c8ebdc..1d7d8b4c1 100644 --- a/src/sign/index.ts +++ b/src/sign/index.ts @@ -63,7 +63,7 @@ export default class Client { message.timestamp = parseInt((Date.now() / 1e3).toFixed()); const data: any = { domain, types, message }; const sig = await signer._signTypedData(domain, data.types, message); - console.log('Sign', { address, sig, data }); + // console.log('Sign', { address, sig, data }); return await this.send({ address, sig, data }); } From 52d87f30ab150ea0620fc45d51735785d5d540e5 Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Mon, 31 Oct 2022 17:25:06 +0100 Subject: [PATCH 5/8] remove circular dep --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 2caa582ae..3d9a5765e 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "@ethersproject/hash": "^5.6.1", "@ethersproject/providers": "^5.6.8", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.43", "ajv": "^8.11.0", "ajv-formats": "^2.1.1", "cross-fetch": "^3.1.5", From 2bb2bcb7224eb47666ab9b2a2146b1e39d9b368f Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Mon, 31 Oct 2022 17:25:34 +0100 Subject: [PATCH 6/8] remove webhook schema --- src/schemas/webhook.json | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 src/schemas/webhook.json diff --git a/src/schemas/webhook.json b/src/schemas/webhook.json deleted file mode 100644 index 3bcda6e14..000000000 --- a/src/schemas/webhook.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Webhook", - "definitions": { - "Webhook": { - "title": "Webhook", - "type": "object", - "properties": { - "space": { - "type": "string", - "title": "space" - }, - "url": { - "type": "string", - "title": "url", - "format": "url" - } - }, - "required": [ - "space", - "url" - ], - "additionalProperties": false - } - } -} \ No newline at end of file From 8b06792e129ec8b9f1b908a65982a89d0146df7f Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Mon, 31 Oct 2022 17:29:33 +0100 Subject: [PATCH 7/8] refactor --- src/sign/index.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sign/index.ts b/src/sign/index.ts index 1d7d8b4c1..a0a9dc126 100644 --- a/src/sign/index.ts +++ b/src/sign/index.ts @@ -60,20 +60,18 @@ export default class Client { const signer = web3?.getSigner ? web3.getSigner() : web3; if (!message.from) message.from = address; if (!message.timestamp) - message.timestamp = parseInt((Date.now() / 1e3).toFixed()); + message.timestamp = parseInt((Date.now() / 1e3).toFixed()); const data: any = { domain, types, message }; const sig = await signer._signTypedData(domain, data.types, message); // console.log('Sign', { address, sig, data }); - return await this.send({ address, sig, data }); } async send(envelop) { const webhookAction = Object.keys(envelop.data.types).filter(key => ['Webhook', 'RemoveWebhook'].includes(key)).length - const url = - webhookAction > 0 - ? `${this.webhookAddress}/api/subscribers` - : `${this.hubAddress}/api/msg`; + const url = webhookAction + ? `${this.webhookAddress}/api/subscribers` + : `${this.hubAddress}/api/msg`; const init = { method: 'POST', headers: { From f7bd4014023ba0a4b79bf181e9941b8c4d0d7728 Mon Sep 17 00:00:00 2001 From: Zuza Zuber Date: Mon, 31 Oct 2022 17:37:35 +0100 Subject: [PATCH 8/8] fix constructor --- src/sign/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sign/index.ts b/src/sign/index.ts index a0a9dc126..52b536946 100644 --- a/src/sign/index.ts +++ b/src/sign/index.ts @@ -47,12 +47,10 @@ export const domain = { }; export default class Client { - readonly hubAddress: string; - readonly webhookAddress: string; + readonly address: string; constructor(address: string = hubs[0]) { - this.hubAddress = address; - this.webhookAddress = 'http://localhost:3000'; + this.address = address; } async sign(web3: Web3Provider | Wallet, address: string, message, types) { @@ -68,10 +66,12 @@ export default class Client { } async send(envelop) { - const webhookAction = Object.keys(envelop.data.types).filter(key => ['Webhook', 'RemoveWebhook'].includes(key)).length + const webhookAction = Object.keys(envelop.data.types).filter((key) => + ['Webhook', 'RemoveWebhook'].includes(key) + ).length; const url = webhookAction - ? `${this.webhookAddress}/api/subscribers` - : `${this.hubAddress}/api/msg`; + ? `${this.address}/api/subscribers` + : `${this.address}/api/msg`; const init = { method: 'POST', headers: {