diff --git a/.github/workflows/dapp-deploy.yml b/.github/workflows/dapp-deploy.yml index ab32d75..9e7e9b3 100644 --- a/.github/workflows/dapp-deploy.yml +++ b/.github/workflows/dapp-deploy.yml @@ -41,14 +41,26 @@ jobs: else echo "clean_tag=dev" | tee -a $GITHUB_OUTPUT fi + read-ipfs-gateway: + runs-on: ubuntu-latest + environment: ${{ github.event.inputs.environment }} + outputs: + web3telegram_ipfs_gateway: ${{ vars.WEB3TELEGRAM_IPFS_GATEWAY }} + steps: + - name: WEB3TELEGRAM_IPFS_GATEWAY + run: echo "WEB3TELEGRAM_IPFS_GATEWAY=$WEB3TELEGRAM_IPFS_GATEWAY" + env: + WEB3TELEGRAM_IPFS_GATEWAY: ${{ vars.WEB3TELEGRAM_IPFS_GATEWAY }} + docker-publish: uses: iExecBlockchainComputing/github-actions-workflows/.github/workflows/docker-build.yml@docker-build-v3.3.0 - needs: [extract-tag] + needs: [extract-tag, read-ipfs-gateway] with: image-name: 'iexechub/web3telegram-dapp' registry: 'docker.io' dockerfile: 'dapp/Dockerfile' context: 'dapp' + build-args: WEB3TELEGRAM_IPFS_GATEWAY=${{ needs.read-ipfs-gateway.outputs.web3telegram_ipfs_gateway }} security-scan: false hadolint: true push: true diff --git a/dapp/.env.override b/dapp/.env.override index 7e45e38..8760214 100644 --- a/dapp/.env.override +++ b/dapp/.env.override @@ -1,3 +1,4 @@ +WEB3TELEGRAM_IPFS_GATEWAY=https://ipfs-gateway.v8-bellecour.iex.ec IEXEC_IN=/path/to/input/directory IEXEC_OUT=/path/to/output/directory IEXEC_DATASET_FILENAME="protectedData.zip" diff --git a/dapp/Dockerfile b/dapp/Dockerfile index 2f0040a..369ede6 100644 --- a/dapp/Dockerfile +++ b/dapp/Dockerfile @@ -1,4 +1,6 @@ FROM node:22-alpine3.22 +ARG WEB3TELEGRAM_IPFS_GATEWAY +ENV WEB3TELEGRAM_IPFS_GATEWAY=$WEB3TELEGRAM_IPFS_GATEWAY WORKDIR /app COPY package*.json ./ RUN npm ci --production diff --git a/dapp/README.md b/dapp/README.md index 01c13de..9511bef 100644 --- a/dapp/README.md +++ b/dapp/README.md @@ -19,6 +19,7 @@ fill in the environment variables: - **IEXEC_DATASET\_\\_FILENAME**: The name of the data file for dataset at index (starting from 1) that you place in the **IEXEC_IN** directory. - **IEXEC_APP_DEVELOPER_SECRET**: A JSON string with the following keys: - **TELEGRAM_BOT_TOKEN**: The API key of the telegram bot used to send the message. +- **WEB3TELEGRAM_IPFS_GATEWAY**: Base URL of the iExec IPFS gateway used to download encrypted message content (must match the chain where content was pinned, e.g. `https://ipfs-gateway.v8-bellecour.iex.ec` or `https://ipfs-gateway.arbitrum-mainnet.iex.ec`). Baked into release images via the deploy workflow; required for local runs. - **IEXEC_REQUESTER_SECRET_1**: A JSON string with the following keys: - **telegramContentMultiAddr**: Multiaddress pointing to the encrypted message content to send. - **telegramContentEncryptionKey**: The encryption key used to encrypt the content. @@ -43,9 +44,12 @@ The Dapp will send a telegram message using the object and content specified in 1. **Build the Docker image**: Navigate to the `/web3telegram/dapp` directory of the project and run the following command to build the Docker image: ```sh - docker build . --tag web3telegram-dapp + docker build . --tag web3telegram-dapp \ + --build-arg WEB3TELEGRAM_IPFS_GATEWAY=https://ipfs-gateway.v8-bellecour.iex.ec ``` + Use the gateway URL for the same chain as your pinned content (see `src/config/config.ts` `ipfsGateway` per chain). + 2. **Create local directories**: In your terminal, execute the following commands to create two local directories on your machine: ```sh @@ -69,6 +73,7 @@ The Dapp will send a telegram message using the object and content specified in -e IEXEC_IN=/iexec_in \ -e IEXEC_OUT=/iexec_out \ -e IEXEC_DATASET_FILENAME=data.zip \ + -e WEB3TELEGRAM_IPFS_GATEWAY=https://ipfs-gateway.v8-bellecour.iex.ec \ IEXEC_REQUESTER_SECRET_1='{"telegramContentEncryptionKey":"telegram_content_encryption_key","telegramContentMultiAddr":"encrypted_telegram_content_multiaddress","senderName":"sender_name","contentType":"text/plain"}' \ web3telegram-dapp ``` diff --git a/dapp/src/decryptContent.js b/dapp/src/decryptContent.js index 8f588a6..390a7a5 100644 --- a/dapp/src/decryptContent.js +++ b/dapp/src/decryptContent.js @@ -2,11 +2,19 @@ import { Buffer } from 'buffer'; import fetch from 'node-fetch'; import forge from 'node-forge'; -const DEFAULT_IPFS_GATEWAY = 'https://ipfs-gateway.v8-bellecour.iex.ec'; +export const resolveIpfsGatewayUrl = () => { + const url = process.env.WEB3TELEGRAM_IPFS_GATEWAY; + if (url == null || String(url).trim() === '') { + throw new Error( + 'WEB3TELEGRAM_IPFS_GATEWAY environment variable is not set.' + ); + } + return String(url).trim(); +}; export const downloadEncryptedContent = async ( multiaddr, - { ipfsGateway = DEFAULT_IPFS_GATEWAY } = {} + { ipfsGateway = resolveIpfsGatewayUrl() } = {} ) => { try { const publicUrl = `${ipfsGateway}${multiaddr.replace('/p2p/', '/ipfs/')}`; diff --git a/dapp/tests/e2e/app.test.js b/dapp/tests/e2e/app.test.js index 4a63d4d..646fd09 100644 --- a/dapp/tests/e2e/app.test.js +++ b/dapp/tests/e2e/app.test.js @@ -36,6 +36,9 @@ describe('sendTelegram', () => { beforeEach(() => { // protected data setup process.env.IEXEC_DATASET_FILENAME = 'data-chatId.zip'; + process.env.WEB3TELEGRAM_IPFS_GATEWAY = + process.env.WEB3TELEGRAM_IPFS_GATEWAY || + 'https://ipfs-gateway.v8-bellecour.iex.ec'; // developer secret setup process.env.IEXEC_APP_DEVELOPER_SECRET = JSON.stringify({ TELEGRAM_BOT_TOKEN: process.env.TELEGRAM_BOT_TOKEN, diff --git a/dapp/tests/unit/decryptContent.test.js b/dapp/tests/unit/decryptContent.test.js index 0aead62..47a8f75 100644 --- a/dapp/tests/unit/decryptContent.test.js +++ b/dapp/tests/unit/decryptContent.test.js @@ -5,8 +5,11 @@ import { IExec } from 'iexec'; import { decryptContent, downloadEncryptedContent, + resolveIpfsGatewayUrl, } from '../../src/decryptContent'; +const TEST_IPFS_GATEWAY = 'https://ipfs-gateway.v8-bellecour.iex.ec'; + describe('decryptContent', () => { it('should decrypt message correctly', async () => { const iexec = new IExec({ @@ -33,21 +36,42 @@ describe('decryptContent', () => { }); }); +describe('resolveIpfsGatewayUrl', () => { + const prev = process.env.WEB3TELEGRAM_IPFS_GATEWAY; + + afterAll(() => { + if (prev === undefined) { + delete process.env.WEB3TELEGRAM_IPFS_GATEWAY; + } else { + process.env.WEB3TELEGRAM_IPFS_GATEWAY = prev; + } + }); + + it('should throw if WEB3TELEGRAM_IPFS_GATEWAY is not set', () => { + delete process.env.WEB3TELEGRAM_IPFS_GATEWAY; + expect(() => resolveIpfsGatewayUrl()).toThrow( + Error('WEB3TELEGRAM_IPFS_GATEWAY environment variable is not set.') + ); + }); +}); + describe('downloadEncryptedContent', () => { it('should return the encrypted content', async () => { const content = `{"JSONPath":"$['rates']['GBP']","body":"","dataType":"number","dataset":"0x0000000000000000000000000000000000000000","headers":{},"method":"GET","url":"https://api.exchangerate.host/latest?base=USD&symbols=GBP"}`; const textEncoder = new TextEncoder(); const actualContent = await textEncoder.encode(content); const multiaddr = '/ipfs/Qmb1JLTVp4zfRMPaori9htzzM9D3B1tG8pGbZYTRC1favA'; - const expectedContent = await downloadEncryptedContent(multiaddr); + const expectedContent = await downloadEncryptedContent(multiaddr, { + ipfsGateway: TEST_IPFS_GATEWAY, + }); expect(actualContent).toEqual(expectedContent); }); it('should throw an error if the content cannot be loaded', async () => { const multiaddr = '/ipfs/QmYhXeg4p4D729m432t8b9877b35e756a82749723456789invalid'; - await expect(downloadEncryptedContent(multiaddr)).rejects.toThrow( - Error('Failed to download encrypted content') - ); + await expect( + downloadEncryptedContent(multiaddr, { ipfsGateway: TEST_IPFS_GATEWAY }) + ).rejects.toThrow(Error('Failed to download encrypted content')); }); });