diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..1c960a98e --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,37 @@ +name: Push Workflow +on: push + +jobs: + messenger-demo-deploy: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/${{ vars.STAGING_BRANCH }}' + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + registry-url: 'https://npm.pkg.github.com' + node-version: 18.0.0 + cache: 'yarn' + - name: Prepare SSH + run: | + mkdir ~/.ssh + echo "${{ secrets.STAGING_HOST_SSH }}" > ~/.ssh/known_hosts + echo "${{ secrets.DO_SSH_KEY }}" > ./ssh-key + chmod 600 ./ssh-key + - name: Create .env file + run: | + echo "REACT_APP_ADDR_ENS_SUBDOMAIN=.beta-addr.dm3.eth" >> ./.env + echo "REACT_APP_BACKEND=http://${{ secrets.STAGING_HOST }}" >> ./.env + echo "REACT_APP_DEFAULT_DELIVERY_SERVICE=beta-ds.dm3.eth" >> ./.env + echo "REACT_APP_DEFAULT_SERVICE=http://${{ secrets.STAGING_HOST }}" >> ./.env + echo "REACT_APP_ETHEREUM_PROVIDER=${{ secrets.REACT_APP_ETHEREUM_PROVIDER }}" >> ./.env + echo "REACT_APP_PROFILE_BASE_URL=http://dm3-beta2-resolver.herokuapp.com" >> ./.env + echo "REACT_APP_RESOLVER_BACKEND=http://dm3-beta2-resolver.herokuapp.com" >> ./.env + echo "REACT_APP_USER_ENS_SUBDOMAIN=.beta-user.dm3.eth" >> ./.env + echo "REACT_APP_WALLET_CONNECT_PROJECT_ID=${{ secrets.REACT_APP_WALLET_CONNECT_PROJECT_ID }}" >> ./.env + echo "RESOLVER_ADDR=0x45F7Ed7d05c563D408898A80d9C705CC3328D2EF" >> ./.env + echo WEB_PORT=80 >> ./.env + - name: Sync files + run: | + rsync -avz -e 'ssh -i ./ssh-key' ./ app@${{ secrets.STAGING_HOST }}:/home/app/ + diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index d72e8e835..bbb83fce8 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -4,6 +4,7 @@ on: push jobs: code-quality: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v3 @@ -22,7 +23,7 @@ jobs: build: runs-on: ubuntu-latest - + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v3 @@ -50,6 +51,7 @@ jobs: path: packages/lib/**/schema/ backend-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -63,6 +65,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} integration-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -76,6 +79,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} lib-crypto-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -89,6 +93,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} lib-delivery-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -102,6 +107,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} lib-messaging-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -115,6 +121,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} lib-profile-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -128,6 +135,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} lib-shared-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -141,6 +149,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} lib-storage-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -154,6 +163,7 @@ jobs: package-pat: ${{ secrets.PACKAGE_PAT }} offchain-resolver-test: runs-on: ubuntu-latest + if: github.ref != 'refs/heads/${{ vars.STAGING_BRANCH }}' needs: build defaults: run: @@ -164,53 +174,4 @@ jobs: uses: ./test-action with: workspace-name: 'dm3-offchain-resolver' - package-pat: ${{ secrets.PACKAGE_PAT }} - messenger-demo-deploy: - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/new-ui' - steps: - # Check-out your repository. - - name: Checkout - uses: actions/checkout@v2 - - name: Create env file - run: | - echo "REACT_APP_ADDR_ENS_SUBDOMAIN=.beta-addr.dm3.eth" >> ./packages/messenger-demo/.env - echo "REACT_APP_BACKEND=https://dm3-beta2.herokuapp.com" >> ./packages/messenger-demo/.env - echo "REACT_APP_DEFAULT_DELIVERY_SERVICE=beta-ds.dm3.eth" >> ./packages/messenger-demo/.env - echo "REACT_APP_DEFAULT_SERVICE=https://dm3-beta2.herokuapp.com" >> ./packages/messenger-demo/.env - echo "REACT_APP_ETHEREUM_PROVIDER=${{ secrets.REACT_APP_ETHEREUM_PROVIDER }}" >> ./packages/messenger-demo/.env - echo "REACT_APP_PROFILE_BASE_URL=https://dm3-beta2-resolver.herokuapp.com" >> ./packages/messenger-demo/.env - echo "REACT_APP_RESOLVER_BACKEND=https://dm3-beta2-resolver.herokuapp.com" >> ./packages/messenger-demo/.env - echo "REACT_APP_USER_ENS_SUBDOMAIN=.beta-user.dm3.eth" >> ./packages/messenger-demo/.env - echo "REACT_APP_WALLET_CONNECT_PROJECT_ID=${{ secrets.REACT_APP_WALLET_CONNECT_PROJECT_ID }}" >> ./packages/messenger-demo/.env - echo "RESOLVER_ADDR=0x45F7Ed7d05c563D408898A80d9C705CC3328D2EF" >> ./packages/messenger-demo/.env - - name: Build, Push and Release a Docker container to Heroku. # Your custom step name - uses: gonuit/heroku-docker-deploy@v1.3.3 # GitHub action name (leave it as it is). - with: - # Below you must provide variables for your Heroku app. - - # The email address associated with your Heroku account. - # If you don't want to use repository secrets (which is recommended) you can do: - # email: my.email@example.com - email: ${{ secrets.HEROKU_EMAIL }} - - # Heroku API key associated with provided user's email. - # Api Key is available under your Heroku account settings. - heroku_api_key: ${{ secrets.HEROKU_API_KEY }} - - # Name of the heroku application to which the build is to be sent. - heroku_app_name: ${{ secrets.HEROKU_APP_NAME }} - - # (Optional, default: "./") - # Dockerfile directory. - # For example, if you have a Dockerfile in the root of your project, leave it as follows: - dockerfile_directory: ./ - - # (Optional, default: "Dockerfile") - # Dockerfile name. - dockerfile_name: ./packages/messenger-demo/Dockerfile - # (Optional, default: "web") - # Select the process type for which you want the docker container to be uploaded. - # By default, this argument is set to "web". - # For more information look at https://devcenter.heroku.com/articles/process-model - process_type: web + package-pat: ${{ secrets.PACKAGE_PAT }} \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..193168926 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,7 @@ +FROM --platform=linux/amd64 node:18-alpine +WORKDIR /app +COPY . . +RUN apk add --update python3 make g++\ + && rm -rf /var/cache/apk/* +RUN yarn install +RUN yarn build diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 000000000..692dc3660 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +docker build --progress=plain -t dm3-backend -f ./docker/Dockerfile . \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 000000000..803db205e --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,58 @@ +version: "3.1" +services: + + backend: + image: dm3org/dm3-backend:v0.2.1 + command: yarn workspace dm3-backend start + depends_on: + - db + environment: + - REDIS_URL=redis://db:6379 + + db: + image: redis + restart: always + + offchain-resolver-db: + image: postgres + restart: always + container_name: offchain_resolver_db + environment: + POSTGRES_PASSWORD: example + ports: + - '5432:5432' + + offchain-resolver: + image: dm3-backend + command: yarn workspace dm3-offchain-resolver start + depends_on: + - offchain-resolver-db + environment: + DATABASE_URL: postgresql://postgres:example@offchain-resolver-db:5432 + ports: + - '8082:8082' + + web: + image: dm3-backend + command: yarn workspace messenger-demo start + ports: + - '${WEB_PORT}:8080' + + ccip-resolver: + image: ccip-resolver + restart: always + depends_on: + - offchain-resolver + environment: + SIGNER_PRIVATE_KEY: ${SIGNER_PRIVATE_KEY} + LOG_LEVEL: debug + CONFIG: | + { + "0x5e0F81D5ca51D309B3A046FAeea70C4C70Df8079": { + "type": "signing", + "handlerUrl": "http://offchain-resolver:8081" + } + } + PORT: 8181 + ports: + - '8181:8181' diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 9a1ea6530..5cb4b9ec3 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -1,8 +1,10 @@ FROM node:18-alpine WORKDIR /app COPY . . - +RUN apk add --update python3 make g++\ + && rm -rf /var/cache/apk/* +RUN ls +RUN pwd RUN yarn install -# RUN yarn build -CMD cd packages/backend && yarn start -EXPOSE 3000 \ No newline at end of file +RUN yarn build +CMD yarn workspace messenger-demo start diff --git a/packages/backend/src/persistance/getDatabase.ts b/packages/backend/src/persistance/getDatabase.ts index 49117f9e9..5d7cc3fcf 100644 --- a/packages/backend/src/persistance/getDatabase.ts +++ b/packages/backend/src/persistance/getDatabase.ts @@ -36,7 +36,7 @@ export async function getRedisClient(logger: winston.Logger) { url, ...socketConf, } - : {}, + : { url }, ); client.on('error', (err) => { diff --git a/packages/billboard-client/src/persitance/getDatabase.ts b/packages/billboard-client/src/persitance/getDatabase.ts index bae610238..9e070839e 100644 --- a/packages/billboard-client/src/persitance/getDatabase.ts +++ b/packages/billboard-client/src/persitance/getDatabase.ts @@ -22,7 +22,7 @@ export async function getRedisClient(logger: winston.Logger) { url, ...socketConf, } - : {}, + : { url }, ); client.on('error', (err) => { diff --git a/packages/offchain-resolver/package.json b/packages/offchain-resolver/package.json index 9bce8a08e..36a13566b 100644 --- a/packages/offchain-resolver/package.json +++ b/packages/offchain-resolver/package.json @@ -26,7 +26,8 @@ "scripts": { "docker:up": "docker-compose up -d", "test": "yarn docker:up && yarn prisma:migrate && yarn mocha --require ts-node/register --extension .test.ts --recursive ./src", - "start": "yarn ts-node --transpile-only ./src/index.ts", + "start:dev": "yarn prisma:migrate && yarn ts-node --transpile-only ./src/index.ts", + "start": "yarn prisma:migrate && node ./dist", "build": "yarn prisma generate --schema=./src/persistance/schema.prisma && yarn tsc", "prisma:migrate": "yarn prisma migrate dev --name init --schema src/persistance/schema.prisma" }, diff --git a/packages/offchain-resolver/src/http/handleCcipRequest/encoding/decodeRequest.ts b/packages/offchain-resolver/src/http/handleCcipRequest/encoding/decodeRequest.ts index 72ca364ef..1b3af660f 100644 --- a/packages/offchain-resolver/src/http/handleCcipRequest/encoding/decodeRequest.ts +++ b/packages/offchain-resolver/src/http/handleCcipRequest/encoding/decodeRequest.ts @@ -3,6 +3,7 @@ import { DecodedCcipRequest } from '../types'; import { decodeAddr } from './decode/decodeAddr'; import { decodeText } from './decode/decodeText'; import { getResolverInterface } from './getResolverInterface'; +import { TransactionDescription } from 'ethers/lib/utils'; /** Decodes a given calldata string and returns a DecodedCcipRequest object containing the signature and request. @@ -14,14 +15,16 @@ export function decodeRequest(calldata: string): DecodedCcipRequest { try { const textResolver = getResolverInterface(); - //Parse the calldata returned by a contra - const [ensName, data] = textResolver.parseTransaction({ - data: calldata, - }).args; + //Parse the calldata returned by a contrat + const [ensName, data] = ( + textResolver.parseTransaction({ + data: calldata, + }) as TransactionDescription + ).args; const { signature, args } = textResolver.parseTransaction({ data, - }); + }) as TransactionDescription; switch (signature) { case 'text(bytes32,string)': diff --git a/packages/offchain-resolver/src/http/handleCcipRequest/encoding/getResolverInterface.ts b/packages/offchain-resolver/src/http/handleCcipRequest/encoding/getResolverInterface.ts index 94f380a05..67af6835d 100644 --- a/packages/offchain-resolver/src/http/handleCcipRequest/encoding/getResolverInterface.ts +++ b/packages/offchain-resolver/src/http/handleCcipRequest/encoding/getResolverInterface.ts @@ -2,8 +2,32 @@ import { ethers } from 'ethers'; export function getResolverInterface() { return new ethers.utils.Interface([ - 'function resolve(bytes calldata name, bytes calldata data) external view returns(bytes)', + // eslint-disable-next-line max-len + 'function resolveWithContext(bytes calldata name,bytes calldata data,bytes calldata context) external view returns (bytes memory result)', + // eslint-disable-next-line max-len + 'function resolveWithProof(bytes calldata response, bytes calldata extraData) external view returns (bytes memory)', + //Text 'function text(bytes32 node, string calldata key) external view returns (string memory)', + //Address 'function addr(bytes32 node) external view returns (address)', + //ABI + // eslint-disable-next-line max-len + 'function ABI(bytes calldata context,bytes32 node,uint256 contentTypes) external view returns(uint256, bytes memory)', + //ContentHash + 'function contenthash(bytes calldata context, bytes32 node) external view returns (bytes memory)', + 'function contenthash(bytes32 node) external view returns (bytes memory)', + //Interface + // eslint-disable-next-line max-len + 'function interfaceImplementer (bytes calldata context, bytes32 node, bytes4 interfaceID) external view returns (address)', + //Name + + 'function name(bytes calldata context ,bytes32 node) external view returns (string memory)', + //Pubkey + 'function pubkey(bytes calldata context ,bytes32 node) external view returns (bytes memory x, bytes memory y)', + //DNS + // eslint-disable-next-line max-len + 'function dnsRecord(bytes calldata context,bytes32 node,bytes32 name,uint16 resource) public view returns(bytes memory)', + 'function hasDNSRecords(bytes calldata context, bytes32 node, bytes32 name) public view returns (bool)', + 'function zonehash(bytes calldata context, bytes32 node) external view returns (bytes memory)', ]); } diff --git a/packages/offchain-resolver/src/http/handleCcipRequest/handleCcipRequest.ts b/packages/offchain-resolver/src/http/handleCcipRequest/handleCcipRequest.ts index 8af346f68..4ceadfe98 100644 --- a/packages/offchain-resolver/src/http/handleCcipRequest/handleCcipRequest.ts +++ b/packages/offchain-resolver/src/http/handleCcipRequest/handleCcipRequest.ts @@ -1,6 +1,7 @@ import express from 'express'; import { handleAddr } from './handler/handleAddr'; import { handleText } from './handler/resolveText'; +import { ethers } from 'ethers'; export async function handleCcipRequest( req: express.Request, signature: string, @@ -9,7 +10,10 @@ export async function handleCcipRequest( switch (signature) { case 'text(bytes32,string)': req.app.locals.logger.info('Reading text(bytes32,string)'); - return await handleText(req.app.locals.db, request); + return ethers.utils.defaultAbiCoder.encode( + ['string'], + [await handleText(req.app.locals.db, request)], + ); case 'addr(bytes32)': req.app.locals.logger.info('Reading addr(bytes32))'); return await handleAddr(req.app.locals.db, request); diff --git a/packages/offchain-resolver/src/http/resolverEndpoint.ts b/packages/offchain-resolver/src/http/resolverEndpoint.ts index 5d20b504c..1eb41284e 100644 --- a/packages/offchain-resolver/src/http/resolverEndpoint.ts +++ b/packages/offchain-resolver/src/http/resolverEndpoint.ts @@ -34,7 +34,7 @@ export function resolverEndpoint() { res.status(404).send({ message: 'Record not found' }); } else { - res.send({ response }); + res.send(response); } } catch (e) { req.app.locals.logger.warn((e as Error).message); diff --git a/packages/offchain-resolver/src/index.ts b/packages/offchain-resolver/src/index.ts index 304e23de9..0a3cca0af 100644 --- a/packages/offchain-resolver/src/index.ts +++ b/packages/offchain-resolver/src/index.ts @@ -7,8 +7,7 @@ import winston from 'winston'; import { getDatabase } from './persistance/getDatabase'; import { resolverEndpoint } from './http/resolverEndpoint'; import { getWeb3Provider } from './utils/getWeb3Provider'; -import { getSigner } from './utils/getSigner'; -import { readKeyFromEnv } from './utils/readKeyEnv'; + import { profile } from './http/profile'; dotenv.config(); diff --git a/packages/offchain-resolver/src/persistance/profile/getUserProfile.ts b/packages/offchain-resolver/src/persistance/profile/getUserProfile.ts new file mode 100644 index 000000000..fe7b74f12 --- /dev/null +++ b/packages/offchain-resolver/src/persistance/profile/getUserProfile.ts @@ -0,0 +1,28 @@ +/* eslint-disable max-len */ +import { ethers } from 'ethers'; +import { PrismaClient, Prisma } from '@prisma/client'; +import { UserProfile } from 'dm3-lib-profile/dist.backend'; + +/** + * + * @param {db} db - Prisma client + * @param {string} name - Ethereum name + * @returns {Promise} A promise that resolves to the user profile object or null if the user is not found + */ + +export function getUserProfile(db: PrismaClient) { + return async (name: string) => { + const profileContainer = await db.profileContainer.findUnique({ + where: { + nameHash: ethers.utils.namehash(name), + }, + }); + + // profileContainer.profile may be a string or an object. + return profileContainer && profileContainer.profile + ? (JSON.parse( + JSON.stringify(profileContainer.profile), + ) as UserProfile) + : null; + }; +}