From 2a6ba2aed81c5fabc228af24872366d478d18b70 Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Fri, 23 Aug 2024 10:31:05 -0500 Subject: [PATCH] Refactor example to use Node --- examples/.node-version | 1 + examples/.nvmrc | 1 + examples/download.js | 21 +++++++++++ examples/fetch-bundle.py | 71 -------------------------------------- examples/package.json | 6 ++++ examples/requirements.txt | 2 -- examples/test_bundle.jsonl | 5 --- examples/test_file.txt | 1 + examples/upload-bundle.py | 56 ------------------------------ examples/upload.js | 26 ++++++++++++++ 10 files changed, 56 insertions(+), 134 deletions(-) create mode 100644 examples/.node-version create mode 100644 examples/.nvmrc create mode 100644 examples/download.js delete mode 100644 examples/fetch-bundle.py create mode 100644 examples/package.json delete mode 100644 examples/requirements.txt delete mode 100644 examples/test_bundle.jsonl create mode 100644 examples/test_file.txt delete mode 100644 examples/upload-bundle.py create mode 100644 examples/upload.js diff --git a/examples/.node-version b/examples/.node-version new file mode 100644 index 0000000..9075659 --- /dev/null +++ b/examples/.node-version @@ -0,0 +1 @@ +20.15.0 diff --git a/examples/.nvmrc b/examples/.nvmrc new file mode 100644 index 0000000..9075659 --- /dev/null +++ b/examples/.nvmrc @@ -0,0 +1 @@ +20.15.0 diff --git a/examples/download.js b/examples/download.js new file mode 100644 index 0000000..e6574e7 --- /dev/null +++ b/examples/download.js @@ -0,0 +1,21 @@ +const BUNDLE_ID = process.env.BUNDLE_ID; + +if (!BUNDLE_ID) { + console.error("BUNDLE_ID must be present in the environment"); + process.exit(1); +} + +console.log(`Downloading bundle: ${BUNDLE_ID}`); + +const url = `http://0.0.0.0:5558/files/${BUNDLE_ID}`; + +const response = await fetch(url); + +if (!response.ok) { + console.error(`Failed to download bundle. Status code: ${response.status}`); + process.exit(1); +} + +const text = await response.text(); + +console.log(`Downloaded bundle with content: ${text}`); diff --git a/examples/fetch-bundle.py b/examples/fetch-bundle.py deleted file mode 100644 index 2cfd4c4..0000000 --- a/examples/fetch-bundle.py +++ /dev/null @@ -1,71 +0,0 @@ -import pyAesCrypt -import requests -import os - -def decrypt(source, key): - parts = source.rsplit(".aes", 1) - output = parts[0] if len(parts) > 1 else source - key_str = key.decode('utf-8') - pyAesCrypt.decryptFile(source, output, key_str) - return - -def download_messages_bundle(bundle_id, hmac_value, signing_key, aes_key): - """ - Downloads a file from the specified endpoint using a GET request with X-HMAC & X-SIGNING-KEY headers. - - Parameters: - - bundle_id (str): The unique identifier for the file. - - hmac_value (str): The HMAC signature value of the file with `bundle_id`. - - signing_key (str): The key used to sign the bundle. - - aes_key (str): The AES key used to decrypt the downloaded file. - """ - - # Construct the URL with the file's BUNDLE_ID - bundle_id_str = bundle_id.decode('utf-8') - url = f"http://0.0.0.0:5558/files/{bundle_id_str}" - - # Send the GET request with the X-HMAC header - hmac_value_str = hmac_value.decode('utf-8') - headers = {'X-HMAC': hmac_value_str, 'X-SIGNING-KEY': signing_key} - response = requests.get(url, headers=headers) - - if response.status_code == 200: - print("File downloaded successfully.") - # Here, you will want to save the file content to a file. - file_name = f"messages_bundle_{bundle_id_str}.aes" - with open(file_name, 'wb') as file: - file.write(response.content) - - decrypt(file_name, aes_key) - print(f"Successfully decrypted {file_name}") - - else: - print(f"Failed to download file. Status code: {response.status_code} Response: {response.text}") - - -if __name__ == "__main__": - # The assigned bundle_id returned from calling `python upload-bundle.py` - bundle_id = os.environ.get("BUNDLE_ID", "").encode() - if not bundle_id: - print("BUNDLE_ID environment variable is not set.") - exit(1) - - # The value from calculating the hmac signature for the uploaded messages bundle file - hmac_value = os.environ.get("HMAC_VALUE", "").encode() - if not hmac_value: - print("HMAC_VALUE environment variable is not set.") - exit(1) - - # Ensure the signing key is not empty - signing_key = os.environ.get("SIGNING_KEY", "").encode() - if not signing_key: - print("SIGNING_KEY environment variable is not set.") - exit(1) - - # Ensure the aes key is not empty - aes_key = os.environ.get("AES_KEY", "").encode() - if not aes_key: - print("AES_KEY environment variable is not set.") - exit(1) - - download_messages_bundle(bundle_id, hmac_value, signing_key, aes_key) diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..1bb55ed --- /dev/null +++ b/examples/package.json @@ -0,0 +1,6 @@ +{ + "name": "xmtp-message-history-server-example", + "version": "0.0.0", + "private": true, + "type": "module" +} diff --git a/examples/requirements.txt b/examples/requirements.txt deleted file mode 100644 index 7eb26c4..0000000 --- a/examples/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests==2.31.0 -pyAesCrypt===6.1.1 diff --git a/examples/test_bundle.jsonl b/examples/test_bundle.jsonl deleted file mode 100644 index 464bfd6..0000000 --- a/examples/test_bundle.jsonl +++ /dev/null @@ -1,5 +0,0 @@ -{"id": "88facc023d3e4a1db3f9d8e344fb9c5729e34e8df58dfc1bb3e7fcd8efc8e5f1", "group_id": "4a3b711b8fe14d428f8e8b8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e", "decrypted_message_bytes": "48656c6c6f2c20776f726c6421", "sent_at_ns": 1625097600000000000, "kind": 1, "sender_installation_id": "a1b2c3d4e5f678901234567890abcdef", "sender_account_address": "0xAbCdEf1234567890aBcDeF1234567890aBCdEf12", "delivery_status": 1} -{"id": "7fbacc023d3e4a1db3f9d8e344fb9c5729e34e8df58dfc1bb3e7fcd8efc8e5e2", "group_id": "5b3b711b8fe14d428f8e8b8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e8b82b8f", "decrypted_message_bytes": "5768617427732075703f", "sent_at_ns": 1625198600000000000, "kind": 2, "sender_installation_id": "b2c3d4e5f678901234567890abcdefa1", "sender_account_address": "0xBCdEf1234567890aBcDeF1234567890aBCdEf34", "delivery_status": 2} -{"id": "6cbacc023d3e4a1db3f9d8e344fb9c5729e34e8df58dfc1bb3e7fcd8efc8e5d3", "group_id": "6c3b711b8fe14d428f8e8b8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e8b82b8d", "decrypted_message_bytes": "53656520796f7520736f6f6e21", "sent_at_ns": 1625299600000000000, "kind": 1, "sender_installation_id": "c3d4e5f678901234567890abcdefa1b2", "sender_account_address": "0x1234567890aBcDeF1234567890aBCdEf12345678", "delivery_status": 1} -{"id": "5dbacc023d3e4a1db3f9d8e344fb9c5729e34e8df58dfc1bb3e7fcd8efc8e5c4", "group_id": "7d3b711b8fe14d428f8e8b8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e8b82b7c", "decrypted_message_bytes": "4772656174206a6f6221", "sent_at_ns": 1625390600000000000, "kind": 2, "sender_installation_id": "d4e5f678901234567890abcdefa1b2c3", "sender_account_address": "0xf1234567890aBCdEf1234567890aBcDeF1234567", "delivery_status": 2} -{"id": "4ebacc023d3e4a1db3f9d8e344fb9c5729e34e8df58dfc1bb3e7fcd8efc8e5b5", "group_id": "8e3b711b8fe14d428f8e8b8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e8b82b8e", "decrypted_message_bytes": "4c65742773206d6565742075702e", "sent_at_ns": 1625491600000000000, "kind": 1, "sender_installation_id": "e5f678901234567890abcdefa1b2c3d4", "sender_account_address": "0x4567890aBCdEf1234567890aBcDeF1234567890a", "delivery_status": 1} diff --git a/examples/test_file.txt b/examples/test_file.txt new file mode 100644 index 0000000..5dd01c1 --- /dev/null +++ b/examples/test_file.txt @@ -0,0 +1 @@ +Hello, world! \ No newline at end of file diff --git a/examples/upload-bundle.py b/examples/upload-bundle.py deleted file mode 100644 index 0f4f49b..0000000 --- a/examples/upload-bundle.py +++ /dev/null @@ -1,56 +0,0 @@ -import hmac -import hashlib -import pyAesCrypt -import requests -import os - -file_path = "test_bundle.jsonl" - -def encrypt(source, key): - key_str = key.decode('utf-8') - output = source + ".aes" - pyAesCrypt.encryptFile(source, output, key_str) - return output - -def upload_message_bundle(file_path, signing_key): - """ - Uploads a file to the specified endpoint. The file should be encrypted. - - Parameters: - - file_path (str): The path to the file to upload. - - signing_key (str): The key used to sign the HMAC. - """ - # The request payload consisting of a message history bundle - with open(file_path, 'rb') as file: - file_content = file.read() - - # Compute the HMAC - hmac_instance = hmac.new(signing_key, file_content, hashlib.sha256) - hmac_hex = hmac_instance.hexdigest() - print(f"HMAC: {hmac_hex}") - - # Send the request with the HMAC header - headers = {'X-HMAC': hmac_hex} - response = requests.post('http://0.0.0.0:5558/upload', headers=headers, data=file_content) - # Log the response - print(f"Response Status Code: {response.status_code}") - print(f"Response Body: {response.text}") - -if __name__ == "__main__": - # Ensure the signing key is not empty - signing_key = os.environ.get("SIGNING_KEY", "").encode() - if not signing_key: - print("SIGNING_KEY environment variable is not set.") - exit(1) - - # Ensure the aes key is not empty - aes_key = os.environ.get("AES_KEY", "").encode() - if not aes_key: - print("AES_KEY environment variable is not set.") - exit(1) - - encrypted_file = encrypt(file_path, aes_key) - - upload_message_bundle(encrypted_file, signing_key) - - diff --git a/examples/upload.js b/examples/upload.js new file mode 100644 index 0000000..fe7caeb --- /dev/null +++ b/examples/upload.js @@ -0,0 +1,26 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +const file = readFileSync(join(import.meta.dirname, "test_file.txt"), { + encoding: "utf-8", +}); + +console.log(`Uploading file test_file.txt with content: ${file}`); + +const response = await fetch("http://0.0.0.0:5558/upload", { + method: "POST", + body: file, +}); + +if (response.ok) { + console.log("File uploaded successfully"); +} else { + console.error(`Failed to upload file. Status code: ${response.status}`); + process.exit(1); +} + +const bundleId = await response.text(); +console.log(`Bundle ID: ${bundleId}`); +console.log( + `Run "BUNDLE_ID=${bundleId} node download.js" to download the file` +);