Skip to content

Commit d54191c

Browse files
authored
Merge pull request #466 from LIT-Protocol/feat/vincent-2.0-non-dashboard
chore: split commits from Vincent 2.0 Dashboard
2 parents ced4f42 + 466d799 commit d54191c

27 files changed

Lines changed: 640 additions & 1157 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
ability-sdk: patch
3+
registry-sdk: major
4+
registry-backend: major
5+
---
6+
7+
**registry-backend**
8+
9+
- Refactored SIWE authentication middleware
10+
- Simplified app routes and cleaned up route handlers
11+
- Updated ability and policy route handlers
12+
13+
**registry-sdk**
14+
15+
- Switched authentication from JWT to SIWE across all endpoints
16+
- Removed app version management endpoints (editAppVersion, enableAppVersion, disableAppVersion, deleteAppVersion, undeleteAppVersion)
17+
- Removed appVersionCreate and appVersionEdit schemas
18+
19+
**ability-sdk**
20+
21+
- Updated Alchemy chain config for gas sponsorship

packages/apps/registry-backend/eslint.config.cjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ module.exports = [
2121
'debug',
2222
// cors is used in src/lib/express/index.ts but NX doesn't detect it in the build target
2323
'cors',
24+
// Used in packageImporter.ts and getAgentAccount.ts - nx doesn't trace these imports properly
25+
'@zerodev/sdk',
26+
'fs-extra',
27+
'tar',
2428
],
2529
},
2630
],

packages/apps/registry-backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"@lit-protocol/vincent-ability-relay-link": "2.0.0-alpha",
2828
"@lit-protocol/vincent-app-sdk": "2.7.0-alpha",
2929
"@lit-protocol/vincent-contracts-sdk": "^8.1.0",
30-
"@lit-protocol/vincent-registry-sdk": "workspace:*",
30+
"@lit-protocol/vincent-registry-sdk": "6.0.0-alpha.1",
3131
"@t3-oss/env-core": "^0.13.6",
3232
"@zerodev/ecdsa-validator": "^5.4.9",
3333
"@zerodev/permissions": "^5.6.2",
@@ -43,6 +43,7 @@
4343
"normalize-package-data": "^7.0.0",
4444
"query-registry": "4.1.0",
4545
"semver": "^7.7.2",
46+
"siwe": "^3.0.0",
4647
"tar": "^7.4.3",
4748
"validate-npm-package-name": "^6.0.1",
4849
"viem": "2.38.3",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"html":"<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <script type=\"module\" src=\"https://unpkg.com/rapidoc/dist/rapidoc-min.js\"></script>\n <script type=\"text/javascript\" src=\"https://unpkg.com/ethers@5.8.0/dist/ethers.umd.js\">\n </script>\n <style>\n .metamask-button {\n background-color: #f6851b;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n font-weight: bold;\n }\n .metamask-button img {\n margin-right: 8px;\n height: 20px;\n }\n .metamask-container {\n padding: 16px;\n border: 1px solid #ddd;\n border-radius: 4px;\n margin-bottom: 16px;\n }\n .metamask-status {\n margin-top: 8px;\n font-size: 14px;\n }\n .connected {\n color: green;\n }\n .error {\n color: red;\n }\n </style>\n </head>\n\n <body>\n <rapi-doc \n spec-url=\"/openApiJson\" \n theme=\"light\"\n render-style=\"read\"\n show-header=\"false\"\n allow-authentication=\"true\"\n allow-server-selection=\"true\"\n >\n </rapi-doc>\n </body>\n</html>\n"}
1+
{"html":"<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <script type=\"module\" src=\"https://unpkg.com/rapidoc/dist/rapidoc-min.js\"></script>\n <style>\n .metamask-button {\n background-color: #f6851b;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n font-weight: bold;\n }\n .metamask-button img {\n margin-right: 8px;\n height: 20px;\n }\n .metamask-container {\n padding: 16px;\n border: 1px solid #ddd;\n border-radius: 4px;\n margin-bottom: 16px;\n }\n .metamask-status {\n margin-top: 8px;\n font-size: 14px;\n }\n .connected {\n color: green;\n }\n .error {\n color: red;\n }\n </style>\n </head>\n\n <body>\n <rapi-doc\n spec-url=\"/openApiJson\"\n theme=\"light\"\n render-style=\"read\"\n show-header=\"false\"\n allow-authentication=\"true\"\n allow-server-selection=\"true\"\n >\n <div slot=\"auth\" class=\"metamask-container\">\n <h3>SIWE Authentication with Metamask</h3>\n <div>\n <button id=\"connectMetamask\" class=\"metamask-button\">\n <img src=\"https://images.ctfassets.net/clixtyxoaeas/4rnpEzy1ATWRKVBOLxZ1Fm/a74dc1eed36d23d7ea6030383a4d5163/MetaMask-icon-fox.svg\" alt=\"Metamask logo\" />\n Connect with Metamask\n </button>\n <div id=\"metamaskStatus\" class=\"metamask-status\"></div>\n </div>\n <div id=\"authDetails\" style=\"margin-top: 16px; display: none;\">\n <p>Connected Address: <span id=\"connectedAddress\"></span></p>\n <button id=\"generateSiwe\" class=\"metamask-button\" style=\"background-color: #0366d6;\">\n Generate SIWE Authentication\n </button>\n <div id=\"siweStatus\" class=\"metamask-status\"></div>\n </div>\n </div>\n\n <script>\n // Implementation of SIWE functionality\n // Generate a secure random nonce\n function generateNonce() {\n const array = new Uint8Array(16);\n window.crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n }\n\n // EIP-55 checksum address - uses ethers loaded via CDN\n let ethersLoaded = null;\n async function getChecksummedAddress(address) {\n if (!ethersLoaded) {\n // Load ethers from CDN (cached after first load)\n ethersLoaded = import('https://esm.sh/ethers@5.7.2');\n }\n const { utils } = await ethersLoaded;\n return utils.getAddress(address);\n }\n\n // Simple SiweMessage class implementation\n class SiweMessage {\n constructor(params) {\n this.domain = params.domain;\n this.address = params.address;\n this.statement = params.statement;\n this.uri = params.uri;\n this.version = params.version;\n this.chainId = params.chainId;\n this.nonce = params.nonce;\n this.issuedAt = params.issuedAt;\n this.expirationTime = params.expirationTime;\n this.notBefore = params.notBefore;\n this.requestId = params.requestId;\n this.resources = params.resources;\n }\n\n prepareMessage() {\n const header = `${this.domain} wants you to sign in with your Ethereum account:`;\n const uriField = `URI: ${this.uri}`;\n let prefix = [header, this.address].join('\\n');\n const versionField = `Version: ${this.version}`;\n const chainField = `Chain ID: ${this.chainId || '1'}`;\n const nonceField = `Nonce: ${this.nonce}`;\n\n const suffixArray = [uriField, versionField, chainField, nonceField];\n\n if (this.issuedAt) {\n suffixArray.push(`Issued At: ${this.issuedAt}`);\n }\n\n if (this.expirationTime) {\n suffixArray.push(`Expiration Time: ${this.expirationTime}`);\n }\n\n if (this.notBefore) {\n suffixArray.push(`Not Before: ${this.notBefore}`);\n }\n\n if (this.requestId) {\n suffixArray.push(`Request ID: ${this.requestId}`);\n }\n\n if (this.resources) {\n suffixArray.push(\n [`Resources:`, ...this.resources.map(x => `- ${x}`)].join('\\n')\n );\n }\n\n const suffix = suffixArray.join('\\n');\n prefix = [prefix, this.statement].join('\\n\\n');\n if (this.statement !== undefined) {\n prefix += '\\n';\n }\n return [prefix, suffix].join('\\n');\n }\n }\n\n document.addEventListener('DOMContentLoaded', function() {\n const connectBtn = document.getElementById('connectMetamask');\n const statusEl = document.getElementById('metamaskStatus');\n const authDetailsEl = document.getElementById('authDetails');\n const addressEl = document.getElementById('connectedAddress');\n const generateSiweBtn = document.getElementById('generateSiwe');\n const siweStatusEl = document.getElementById('siweStatus');\n\n let currentAccount = null;\n\n // Check if Metamask is installed\n if (typeof window.ethereum === 'undefined') {\n statusEl.textContent = 'Metamask not detected. Please install Metamask extension.';\n statusEl.classList.add('error');\n connectBtn.disabled = true;\n return;\n }\n\n // Connect to Metamask\n connectBtn.addEventListener('click', async function() {\n try {\n statusEl.textContent = 'Connecting to Metamask...';\n\n // Request account access\n const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });\n currentAccount = accounts[0];\n\n // Update UI\n statusEl.textContent = 'Connected to Metamask';\n statusEl.classList.add('connected');\n addressEl.textContent = currentAccount;\n authDetailsEl.style.display = 'block';\n\n // Listen for account changes\n window.ethereum.on('accountsChanged', function (accounts) {\n if (accounts.length === 0) {\n // User disconnected\n currentAccount = null;\n statusEl.textContent = 'Disconnected from Metamask';\n statusEl.classList.remove('connected');\n authDetailsEl.style.display = 'none';\n } else {\n // Account changed\n currentAccount = accounts[0];\n addressEl.textContent = currentAccount;\n statusEl.textContent = 'Connected to Metamask';\n statusEl.classList.add('connected');\n }\n });\n\n } catch (error) {\n console.error(error);\n statusEl.textContent = 'Error connecting to Metamask: ' + error.message;\n statusEl.classList.add('error');\n }\n });\n\n // Generate SIWE message and signature\n generateSiweBtn.addEventListener('click', async function() {\n if (!currentAccount) {\n siweStatusEl.textContent = 'Please connect to Metamask first';\n siweStatusEl.classList.add('error');\n return;\n }\n\n try {\n siweStatusEl.textContent = 'Generating SIWE message...';\n\n // Create a SIWE message using the SiweMessage class\n const domain = window.location.host;\n const origin = window.location.origin;\n const statement = 'Sign in with Ethereum to authenticate with Vincent Registry API';\n\n // Generate a secure nonce\n const nonce = generateNonce();\n\n // Get checksummed address (EIP-55 required by SIWE)\n const checksummedAddress = await getChecksummedAddress(currentAccount);\n\n // Create a SiweMessage object\n const siweMessage = new SiweMessage({\n domain,\n address: checksummedAddress,\n statement,\n uri: origin,\n version: '1',\n chainId: 1,\n nonce,\n issuedAt: new Date().toISOString()\n });\n\n // Prepare the message for signing\n const message = siweMessage.prepareMessage();\n\n // Request signature from user\n siweStatusEl.textContent = 'Please sign the message in Metamask...';\n const signature = await window.ethereum.request({\n method: 'personal_sign',\n params: [message, currentAccount]\n });\n\n // Format the Authorization header value - Base64 encode the JSON payload\n const payload = JSON.stringify({ message, signature });\n const base64Payload = btoa(payload);\n const authHeader = `SIWE ${base64Payload}`;\n\n // Set the API key in RapiDoc\n const rapidoc = document.querySelector('rapi-doc');\n rapidoc.setApiKey('C', authHeader);\n\n siweStatusEl.textContent = 'SIWE authentication generated and applied!';\n siweStatusEl.classList.add('connected');\n\n } catch (error) {\n console.error(error);\n siweStatusEl.textContent = 'Error generating SIWE: ' + error.message;\n siweStatusEl.classList.add('error');\n }\n });\n });\n </script>\n </rapi-doc>\n </body>\n</html>\n"}

packages/apps/registry-backend/src/lib/express/ability/routes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { withSession } from '../../mongo/withSession';
66
import { importPackage, identifySupportedPolicies } from '../../packageImporter';
77
import { requirePackage, withValidPackage } from '../package/requirePackage';
88
import { requireUserIsAuthor } from '../package/requireUserIsAuthor';
9-
import { getPKPInfo, requireVincentAuth, withVincentAuth } from '../vincentAuth';
9+
import { requireVincentAuth, withVincentAuth } from '../vincentAuth';
1010
import { requireAbility, withAbility } from './requireAbility';
1111
import { requireAbilityVersion, withAbilityVersion } from './requireAbilityVersion';
1212

@@ -71,7 +71,7 @@ export function registerRoutes(app: Express) {
7171
const ability = new Ability({
7272
title,
7373
packageName: packageInfo.name,
74-
authorWalletAddress: getPKPInfo(req.vincentUser.decodedJWT).ethAddress,
74+
authorWalletAddress: req.vincentUser.address,
7575
description,
7676
logo,
7777
activeVersion: packageInfo.version,

packages/apps/registry-backend/src/lib/express/app/requireAppVersion.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ export const requireAppVersion = (versionParam = 'version') => {
4545
try {
4646
const appVersion = await AppVersion.findOne({
4747
appId: reqWithApp.vincentApp.appId,
48-
version,
48+
version: parseAppVersion,
4949
});
5050

5151
if (!appVersion) {
5252
debug('App version not found', {
5353
appId: reqWithApp.vincentApp.appId,
54-
appVersion: version,
54+
appVersion: parseAppVersion,
5555
});
5656
res.status(404).end();
5757
return;

packages/apps/registry-backend/src/lib/express/app/requireUserManagesApp.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type { RequestWithVincentUser } from '../vincentAuth';
44
import type { RequestWithApp } from './requireApp';
55

66
import { createDebugger } from '../../../../debug';
7-
import { getPKPInfo } from '../vincentAuth';
87

98
// Combined interface for requests with both app and vincent user
109
export interface RequestWithAppAndVincentUser extends RequestWithApp, RequestWithVincentUser {}
@@ -40,7 +39,7 @@ export const requireUserManagesApp = () => {
4039
return;
4140
}
4241

43-
const userAddress = getPKPInfo(reqWithAppAndUser.vincentUser.decodedJWT).ethAddress;
42+
const userAddress = reqWithAppAndUser.vincentUser.address;
4443

4544
debug('Checking authorization', {
4645
userAddress,

0 commit comments

Comments
 (0)