From 1a437a5ca65e442360894fb74f110196c3b90ef7 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 28 Aug 2024 16:07:33 +0200 Subject: [PATCH] add ProfileValidator to profile endpoint --- packages/offchain-resolver/package.json | 2 + .../src/http/profile.test.ts | 62 ++++++++++++------- .../offchain-resolver/src/http/profile.ts | 20 ++++-- .../profileValidator/ProfileValidator.test.ts | 2 - .../http/profileValidator/ProfileValidator.ts | 4 +- .../src/http/resolverEndpoint.test.ts | 4 +- packages/offchain-resolver/src/index.ts | 3 +- .../src/utils/getLuksoProvider.ts | 7 +++ 8 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 packages/offchain-resolver/src/utils/getLuksoProvider.ts diff --git a/packages/offchain-resolver/package.json b/packages/offchain-resolver/package.json index 976c373ef..54cb7621b 100644 --- a/packages/offchain-resolver/package.json +++ b/packages/offchain-resolver/package.json @@ -8,6 +8,8 @@ "@dm3-org/dm3-lib-crypto": "workspace:^", "@dm3-org/dm3-lib-profile": "workspace:^", "@dm3-org/dm3-lib-shared": "workspace:^", + "@dm3-org/dm3-lib-test-helper": "workspace:^", + "@erc725/erc725.js": "^0.27.1", "@prisma/client": "^4.15.0", "ajv": "^8.16.0", "body-parser": "^1.20.1", diff --git a/packages/offchain-resolver/src/http/profile.test.ts b/packages/offchain-resolver/src/http/profile.test.ts index 4e2293002..8018a3404 100644 --- a/packages/offchain-resolver/src/http/profile.test.ts +++ b/packages/offchain-resolver/src/http/profile.test.ts @@ -42,6 +42,11 @@ describe('Profile', () => { }, ); + const luksoProvider: ethers.providers.JsonRpcProvider = { + //Make the otherwise empty object a valid Provider + _isProvider: true, + } as any; + beforeEach(async () => { prismaClient = await getDbClient(); db = await getDatabase(prismaClient); @@ -72,7 +77,7 @@ describe('Profile', () => { describe('Create Alias', () => { it('Rejects if there is no Profile', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { status, body } = await request(app) .post(`/name`) .send({ @@ -88,7 +93,7 @@ describe('Profile', () => { }); it('Rejects invalid signature', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const offChainProfile1 = app.locals.forTests; @@ -122,10 +127,13 @@ describe('Profile', () => { it('Rejects address with an empty eth balance', async () => { app.use( - profile({ - getBalance: async () => ethers.BigNumber.from(0), - resolveName: async () => offChainProfile.signer, - } as any), + profile( + { + getBalance: async () => ethers.BigNumber.from(0), + resolveName: async () => offChainProfile.signer, + } as any, + luksoProvider, + ), ); const offChainProfile = app.locals.forTests; await request(app) @@ -155,7 +163,7 @@ describe('Profile', () => { }); it('Rejects if subdomain is already claimed', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const profile2: UserProfile = { publicSigningKey: '', publicEncryptionKey: '', @@ -196,10 +204,13 @@ describe('Profile', () => { app2.use(bodyParser.json()); app2.use( - profile({ - getBalance: async () => ethers.BigNumber.from(1), - resolveName: async () => app.locals.forTests.signer, - } as any), + profile( + { + getBalance: async () => ethers.BigNumber.from(1), + resolveName: async () => app.locals.forTests.signer, + } as any, + luksoProvider, + ), ); app2.locals.config = { spamProtection: true }; app2.locals.db = db; @@ -222,7 +233,7 @@ describe('Profile', () => { describe('Store UserProfile by address', () => { it('Rejects invalid schema', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { status, body } = await request(app).post(`/address`).send({ address: SENDER_ADDRESS, signedUserProfile: {}, @@ -232,7 +243,7 @@ describe('Profile', () => { expect(body.error).to.equal('invalid schema'); }); it('Rejects invalid profile', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const userProfile: UserProfile = { publicSigningKey: '0ekgI3CBw2iXNXudRdBQHiOaMpG9bvq9Jse26dButug=', @@ -261,7 +272,7 @@ describe('Profile', () => { }); it('Rejects if subdomain has already a profile', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const offChainProfile1 = await getSignedUserProfile(); @@ -295,7 +306,7 @@ describe('Profile', () => { expect(res2.body.error).to.eql('subdomain already claimed'); }); it('Rejects if subdomain is not supported', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const offChainProfile1 = await getSignedUserProfile(); @@ -332,7 +343,7 @@ describe('Profile', () => { }); it('Stores a valid profile', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { signer, profile: userProfile, @@ -366,10 +377,13 @@ describe('Profile', () => { app.locals.config.spamProtection = false; app.use( - profile({ - ...provider, - resolveName: async () => signer, - } as any), + profile( + { + ...provider, + resolveName: async () => signer, + } as any, + luksoProvider, + ), ); const writeRes = await request(app) @@ -410,13 +424,13 @@ describe('Profile', () => { }); describe('Get User By Account', () => { it('Returns 400 if address in invalid', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { status, body } = await request(app).get(`/fooo`).send(); expect(status).to.equal(400); }); it('Returns 404 if profile does not exists', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { status, body } = await request(app) .get(`/${SENDER_ADDRESS}`) .send(); @@ -424,7 +438,7 @@ describe('Profile', () => { }); it('Rejcts invalid name subdomain', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { signer, profile: userProfile, @@ -461,7 +475,7 @@ describe('Profile', () => { }); it('Returns the profile linked to ', async () => { - app.use(profile(provider)); + app.use(profile(provider, luksoProvider)); const { signer, profile: userProfile, diff --git a/packages/offchain-resolver/src/http/profile.ts b/packages/offchain-resolver/src/http/profile.ts index 22026a31b..8f0b8012f 100644 --- a/packages/offchain-resolver/src/http/profile.ts +++ b/packages/offchain-resolver/src/http/profile.ts @@ -1,13 +1,17 @@ import { checkSignature } from '@dm3-org/dm3-lib-crypto'; import { checkUserProfileWithAddress, schema } from '@dm3-org/dm3-lib-profile'; -import { globalConfig, validateSchema } from '@dm3-org/dm3-lib-shared'; +import { validateSchema } from '@dm3-org/dm3-lib-shared'; import { ethers } from 'ethers'; import express from 'express'; import { SiweMessage } from 'siwe'; +import { ProfileValidator } from './profileValidator/ProfileValidator'; import { SubdomainManager } from './subdomainManager/SubdomainManager'; import { WithLocals } from './types'; -export function profile(web3Provider: ethers.providers.BaseProvider) { +export function profile( + web3Provider: ethers.providers.BaseProvider, + luksoProvider: ethers.providers.BaseProvider, +) { const router = express.Router(); //subdomain manager for address domains const addressSubdomainManager = new SubdomainManager( @@ -257,13 +261,17 @@ export function profile(web3Provider: ethers.providers.BaseProvider) { return res.status(400).send({ error: 'invalid schema' }); } - const profileIsValid = checkUserProfileWithAddress( - signedUserProfile, - address, - ); + //Check if the profile was signed by the owner of the address or an UP + const profileIsValid = await new ProfileValidator( + luksoProvider, + ).validate(signedUserProfile, address); + + //add check for lukso //Check if profile sig is correcet if (!profileIsValid) { + console.error('profile signature invalid'); + console.error(signedUserProfile, address); return res.status(400).send({ error: 'invalid profile' }); } diff --git a/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.test.ts b/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.test.ts index 0e4f7cfc1..1eafc03b9 100644 --- a/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.test.ts +++ b/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.test.ts @@ -8,10 +8,8 @@ import { MockedUserProfile, mockUserProfile, } from '@dm3-org/dm3-lib-test-helper'; -import abiJson from './deployedAbi.json'; import { expect } from 'chai'; import { ethers } from 'ethers'; -import { DM3_PROFILE_KEY } from '../../../../lib/smart-account/dist/KeyStore/constants'; import { ProfileValidator } from './ProfileValidator'; describe('ProfileValidator', () => { diff --git a/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.ts b/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.ts index 3e1618718..4603ed754 100644 --- a/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.ts +++ b/packages/offchain-resolver/src/http/profileValidator/ProfileValidator.ts @@ -16,8 +16,8 @@ import { ethers } from 'ethers'; const ERC1271_SUCCESSVALUE = '0x1626ba7e'; export class ProfileValidator { - private readonly luksoProvider: ethers.providers.Web3Provider; - constructor(luksoProvider: ethers.providers.Web3Provider) { + private readonly luksoProvider: ethers.providers.BaseProvider; + constructor(luksoProvider: ethers.providers.BaseProvider) { this.luksoProvider = luksoProvider; } //Check if a profile is signed by the owner of the address diff --git a/packages/offchain-resolver/src/http/resolverEndpoint.test.ts b/packages/offchain-resolver/src/http/resolverEndpoint.test.ts index 43b6e470d..1f29109a4 100644 --- a/packages/offchain-resolver/src/http/resolverEndpoint.test.ts +++ b/packages/offchain-resolver/src/http/resolverEndpoint.test.ts @@ -42,7 +42,9 @@ describe('Resolver Endpoint', () => { resolveName: async () => profileApp.locals.forTests.signer, }; - profileApp.use(profile(provider)); + const luksoProvider: ethers.providers.JsonRpcProvider = {} as any; + + profileApp.use(profile(provider, luksoProvider)); profileApp.locals.db = db; profileApp.locals.config = { spamProtection: true }; }); diff --git a/packages/offchain-resolver/src/index.ts b/packages/offchain-resolver/src/index.ts index d36224d7b..6b304d239 100644 --- a/packages/offchain-resolver/src/index.ts +++ b/packages/offchain-resolver/src/index.ts @@ -6,6 +6,7 @@ import http from 'http'; import { resolverEndpoint } from './http/resolverEndpoint'; import { getDatabase } from './persistence/getDatabase'; import { getWeb3Provider } from './utils/getWeb3Provider'; +import { getLuksoProvider } from './utils/getLuksoProvider'; import { profile } from './http/profile'; @@ -29,7 +30,7 @@ app.use(bodyParser.json()); }; app.use('/', resolverEndpoint()); - app.use('/profile', profile(getWeb3Provider())); + app.use('/profile', profile(getWeb3Provider(), getLuksoProvider())); })(); const port = process.env.PORT || '8081'; server.listen(port, () => { diff --git a/packages/offchain-resolver/src/utils/getLuksoProvider.ts b/packages/offchain-resolver/src/utils/getLuksoProvider.ts new file mode 100644 index 000000000..1c32c97cb --- /dev/null +++ b/packages/offchain-resolver/src/utils/getLuksoProvider.ts @@ -0,0 +1,7 @@ +import { ethers } from 'ethers'; +import { readKeyFromEnv } from './readKeyEnv'; + +export function getLuksoProvider(): ethers.providers.BaseProvider { + const rpc = readKeyFromEnv('LUKSO_RPC'); + return new ethers.providers.JsonRpcProvider(rpc); +}