#
tokens: 41903/50000 50/54 files (page 1/3)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 3. Use http://codebase.md/0xfreysa/trusted-mcp-server?lines=true&page={x} to view the full context.

# Directory Structure

```
├── Dockerfile
├── gmail_mcp
│   ├── pyproject.toml
│   └── server.py
├── gvproxy.sh
├── Makefile
├── README.md
├── run-enclave.sh
├── setup.sh
├── start.sh
└── verifier
    ├── mcp
    │   └── react-ts-webpack
    │       ├── index.ejs
    │       ├── package.json
    │       ├── pnpm-lock.yaml
    │       ├── postcss.config.js
    │       ├── README.md
    │       ├── src
    │       │   ├── app.css
    │       │   ├── app.tsx
    │       │   ├── components
    │       │   │   ├── alert.tsx
    │       │   │   ├── button.tsx
    │       │   │   ├── shadcn.tsx
    │       │   │   ├── verify-mcp.tsx
    │       │   │   └── verify-tee.tsx
    │       │   └── utils
    │       │       ├── misc.ts
    │       │       ├── requests.ts
    │       │       └── worker.ts
    │       ├── tailwind.config.js
    │       ├── tsconfig.json
    │       └── webpack.js
    ├── package.json
    ├── pnpm-lock.yaml
    ├── rust-toolchain
    ├── serve.json
    ├── src
    │   ├── lib.ts
    │   ├── types.ts
    │   └── utils.ts
    ├── test
    │   ├── assets
    │   │   ├── notary.pem
    │   │   ├── simple_proof_expected.json
    │   │   └── simple_proof_redacted.json
    │   ├── specs
    │   │   ├── full-integration-swapi.spec.ts
    │   │   └── simple-verify.spec.ts
    │   ├── test.ejs
    │   ├── testRunner.ts
    │   ├── utils.ts
    │   └── worker.ts
    ├── tsconfig.compile.json
    ├── tsconfig.json
    ├── utils
    │   ├── build-tlsn-binaries.sh
    │   └── check-wasm.sh
    ├── wasm
    │   ├── pkg
    │   │   ├── package.json
    │   │   ├── README.md
    │   │   ├── snippets
    │   │   │   ├── wasm-bindgen-futures-a509390b5b548b61
    │   │   │   │   └── src
    │   │   │   │       └── task
    │   │   │   │           └── worker.js
    │   │   │   └── wasm-bindgen-rayon-3e04391371ad0a8e
    │   │   │       └── src
    │   │   │           ├── workerHelpers.js
    │   │   │           └── workerHelpers.worker.js
    │   │   ├── tlsn_wasm_bg.wasm
    │   │   ├── tlsn_wasm_bg.wasm.d.ts
    │   │   ├── tlsn_wasm.d.ts
    │   │   └── tlsn_wasm.js
    │   └── remote-attestation-verifier
    │       ├── package.json
    │       ├── remote_attestation_verifier_bg.wasm
    │       ├── remote_attestation_verifier_bg.wasm.d.ts
    │       ├── remote_attestation_verifier.d.ts
    │       └── remote_attestation_verifier.js
    ├── webpack.build.config.js
    └── webpack.web.dev.config.js
```

# Files

--------------------------------------------------------------------------------
/verifier/wasm/pkg/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # TLSNotary WASM bindings
 2 | 
 3 | ## Build
 4 | 
 5 | This crate must be built using the nightly rust compiler with the following flags:
 6 | 
 7 | ```bash
 8 | RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' \
 9 |     rustup run nightly \
10 |     wasm-pack build --target web . -- -Zbuild-std=panic_abort,std
11 | ```
12 | 
13 | 
14 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # React Demo for Notarization and Verification of attestations
 2 | 
 3 | This webapp allows you to
 4 | 
 5 | 1) Generate an attestation for a dummmy request
 6 | 
 7 | 2) Verifies the attestation
 8 | 
 9 | ## 🔴 Todo and bugs
10 | 
11 | ### Notarization
12 | 
13 | - Only works with local websockify server
14 | 
15 | ### Verification
16 | 
17 | - Notary pubkey is hardcoded, should be retrieved from the notary URL and converted from PEM to raw bytes ASN1
18 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Trusted GMail MCP Server
  2 | 
  3 | This is a gmail [MCP](https://modelcontextprotocol.io/introduction) server running inside a secure [AWS Nitro](https://aws.amazon.com/ec2/nitro/) enclave instance. It was originally forked from the [Claude Post](https://github.com/ZilongXue/claude-post) MCP server. Most MCP servers are run locally via the `stdio` transport; we followed [this guide](https://www.ragie.ai/blog/building-a-server-sent-events-sse-mcp-server-with-fastapi) to implement a remote MCP server using `sse` transport.
  4 | 
  5 | ## Connect to the MCP Server
  6 | 
  7 | To use this MCP server, you will need an [app-specific password](https://myaccount.google.com/apppasswords).
  8 | 
  9 | 
 10 | Then simply add the following block to your client's `mcp.json` file.
 11 | ```json
 12 |     "gmail_mcp": {
 13 |       "url": "https://gmail.mcp.freysa.ai/sse/?ADDR=<[email protected]>&ASP=<your app-specific password>"
 14 |     }
 15 | ```
 16 | 
 17 | Note that you might have to restart your client.
 18 | 
 19 | ## Security Notice
 20 | 
 21 | This implementation is a proof of concept. Passing app-specific passwords in URLs is not a secure pattern because:
 22 | - URLs can be logged by proxies, browsers and servers
 23 | - URLs may appear in browser history
 24 | - URLs can be leaked via the Referer header to third-party sites
 25 | 
 26 | Unfortunately, current MCP clients have limitations on how they connect to servers. At the moment of release, MCP specification does not define a standard authentication mechanism for SSE servers. This means we can't use more secure patterns like bearer tokens or other authorization headers that would normally be preferred.
 27 | 
 28 | For additional security, consider:
 29 | 1. Using a dedicated app-specific password just for this purpose
 30 | 2. Accessing this over a secure VPN or private network
 31 | 3. Running your own instance with the provided instructions
 32 | 
 33 | ## Concept
 34 | 
 35 | AWS Nitro Enclaves provide isolated compute environments that enhance security through hardware-based attestation. When code runs in a Nitro Enclave, the platform generates cryptographic measurements of the code's identity and state. These measurements serve as a verifiable guarantee that the code has not been modified and is executing exactly as intended, protecting against tampering or unauthorized modifications. For more information, see this [blog post](https://blog.trailofbits.com/2024/02/16/a-few-notes-on-aws-nitro-enclaves-images-and-attestation/).
 36 | 
 37 | We use [Nitriding](https://github.com/brave/nitriding-daemon) to quickly deploy code in an AWS Nitro TEE.
 38 | 
 39 | ## Verify the code attestation
 40 | 
 41 | To verify that the intended codebase is the one running in our TEE, you must reproduce running it in an AWS Nitro enclave yourself. Instructions to do so are below. Once you have it running, you can verify it using this repository as follows.
 42 | 
 43 | 1. First build the code.
 44 | 
 45 | ```sh
 46 | cd verifier
 47 | 
 48 | pnpm install && pnpm run build
 49 | ```
 50 | 
 51 | 2. Then run the verifier locally.
 52 | ```
 53 | cd mcp/react-ts-webpack
 54 | 
 55 | pnpm i && pnpm run dev
 56 | ```
 57 | 
 58 | 3. Then open `http://localhost:8080/` in your browser. You will be prompted to add two fields
 59 | 
 60 |   (a) the PCR2 hash, which is a hash of the codebase
 61 | 
 62 |   (b) the Code attestation, which is signed by AWS
 63 | 
 64 | 4. Click the "Verify Attestation" button
 65 | 
 66 | ## Run your own instance in a TEE
 67 | 
 68 | You can reproduce running this server in a TEE as follows.
 69 | 
 70 | 1. Use the AWS EC2 console to select a sufficiently large instance and be sure to enable Nitro.
 71 | 
 72 | 2. Make sure that the ports needed by your application are open by checking the security group, in "security" tab of the instance in the ec2 console.
 73 | 
 74 | 3. Clone this repo to your ec2 instance.
 75 | 
 76 | 4. Run the setup script to download all necessary dependencies.
 77 | ```bash
 78 | sudo /setup.sh
 79 | ```
 80 | 
 81 | 5. Allocate more memory for the enclave if necessary.
 82 | ```bash
 83 | sudo nano /etc/nitro_enclaves/allocator.yaml
 84 | 
 85 | sudo systemctl restart nitro-enclaves-allocator.service
 86 | ```
 87 | 
 88 | 6. Run the enclave.
 89 | ```bash
 90 | make
 91 | ```
 92 | 
 93 | 7. Run in production mode.
 94 | ```bash
 95 | make run
 96 | ```
 97 | 
 98 | ## Use your MCP server
 99 | 
100 | To actually use the MCP server, you will also need to run the gvproxy, as follows.
101 | 
102 | ```bash
103 | screen
104 | ./gvproxy.sh
105 | ```
106 | 
107 | Then you can `curl` the healthcheck endpoint to confirm that the MCP server is running in the enclave.
108 | 
109 | ```bash
110 | curl http://127.0.0.1:7047/
111 | ```
112 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/components/button.tsx:
--------------------------------------------------------------------------------

```typescript
1 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/app.css:
--------------------------------------------------------------------------------

```css
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/postcss.config.js:
--------------------------------------------------------------------------------

```javascript
1 | module.exports = {
2 |   plugins: {
3 |     tailwindcss: {},
4 |     autoprefixer: {},
5 |   },
6 | }
7 | 
```

--------------------------------------------------------------------------------
/verifier/test/worker.ts:
--------------------------------------------------------------------------------

```typescript
1 | import * as Comlink from 'comlink';
2 | import init from '../src/lib';
3 | 
4 | Comlink.expose({
5 |   init,
6 | });
7 | 
```

--------------------------------------------------------------------------------
/verifier/test/utils.ts:
--------------------------------------------------------------------------------

```typescript
1 | export function assert(expr: any, msg = 'unknown assertion error') {
2 |   if (!Boolean(expr)) throw new Error(msg);
3 | }
4 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/tailwind.config.js:
--------------------------------------------------------------------------------

```javascript
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 |   content: ['./src/**/*.{js,jsx,ts,tsx}'],
4 |   theme: {
5 |     extend: {},
6 |   },
7 |   plugins: [],
8 | };
9 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/utils/misc.ts:
--------------------------------------------------------------------------------

```typescript
1 | import { twMerge } from 'tailwind-merge';
2 | import { clsx, type ClassValue } from 'clsx';
3 | export function cn(...inputs: ClassValue[]) {
4 |   return twMerge(clsx(inputs));
5 | }
6 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/pkg/snippets/wasm-bindgen-futures-a509390b5b548b61/src/task/worker.js:
--------------------------------------------------------------------------------

```javascript
1 | onmessage = function (ev) {
2 |     let [ia, index, value] = ev.data;
3 |     ia = new Int32Array(ia.buffer);
4 |     let result = Atomics.wait(ia, index, value);
5 |     postMessage(result);
6 | };
7 | 
```

--------------------------------------------------------------------------------
/verifier/tsconfig.compile.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "extends": "./tsconfig.json",
 3 |   "compilerOptions": {
 4 |     "noEmit": false,
 5 |     "declaration": true,
 6 |     "declarationMap": true,
 7 |     "emitDeclarationOnly": true,
 8 |     "sourceMap": true,
 9 |     "outDir": "build"
10 |   }
11 | }
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/utils/worker.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import * as Comlink from 'comlink';
 2 | import init, {
 3 |   verify_code_attestation,
 4 |   verify_attestation_signature,
 5 | } from 'tee-verifier-js';
 6 | 
 7 | Comlink.expose({
 8 |   init,
 9 | 
10 |   verify_code_attestation,
11 |   verify_attestation_signature,
12 | });
13 | 
```

--------------------------------------------------------------------------------
/verifier/serve.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "headers": [{
 3 |     "source": "**/*",
 4 |     "headers": [
 5 |       {
 6 |         "key": "Cross-Origin-Embedder-Policy",
 7 |         "value": "require-corp"
 8 |       }, {
 9 |         "key": "Cross-Origin-Opener-Policy",
10 |         "value": "same-origin"
11 |       }
12 |     ]
13 |   }]
14 | }
```

--------------------------------------------------------------------------------
/verifier/wasm/pkg/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "tlsn-wasm",
 3 |   "type": "module",
 4 |   "version": "0.1.0-alpha.6",
 5 |   "files": [
 6 |     "tlsn_wasm_bg.wasm",
 7 |     "tlsn_wasm.js",
 8 |     "tlsn_wasm.d.ts"
 9 |   ],
10 |   "main": "tlsn_wasm.js",
11 |   "types": "tlsn_wasm.d.ts",
12 |   "sideEffects": [
13 |     "./snippets/*"
14 |   ]
15 | }
```

--------------------------------------------------------------------------------
/gmail_mcp/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "gmail"
 3 | version = "0.1.0"
 4 | description = "Add your description here"
 5 | readme = "README.md"
 6 | requires-python = ">=3.13"
 7 | dependencies = [
 8 |     "mcp[cli]>=1.6.0",
 9 |     "fastapi>=0.109.0",
10 |     "uvicorn>=0.27.0",
11 |     "starlette>=0.36.0",
12 |     "py-dotenv>=0.1",
13 |     "ruff>=0.11.3",
14 |     "loguru>=0.7.3",
15 | ]
16 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/remote-attestation-verifier/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     "name": "remote-attestation-verifier-wasm",
 3 |     "type": "module",
 4 |     "version": "0.1.0-alpha.6",
 5 |     "files": [
 6 |       "remote-attestation-verifier_bg.wasm",
 7 |       "remote-attestation-verifier_bg.wasm.d.ts",
 8 |       "remote-attestation-verifier.js",
 9 |       "remote-attestation-verifier.d.ts"
10 |     ],
11 |     "main": "remote-attestation-verifier.js",
12 |     "types": "remote-attestation-verifier.d.ts",
13 |     "sideEffects": [
14 |       "./snippets/*"
15 |     ]
16 |   }
```

--------------------------------------------------------------------------------
/run-enclave.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | 
 3 | image_eif="$1"
 4 | debug="$2"
 5 | 
 6 | if [ $image_eif == "" ]
 7 | then
 8 | 	echo >&2 "Usage: $0 IMAGE_EIF"
 9 | 	exit 1
10 | fi
11 | 
12 | echo "image_eif: $image_eif"
13 | 
14 | if [ "$debug" = "--debug" ]
15 | then
16 | echo "🚀 Starting enclave in debug mode."
17 | nitro-cli run-enclave \
18 | 	--cpu-count 2 \
19 | 	--memory 3000 \
20 | 	--enclave-cid 4 \
21 | 	--eif-path "$image_eif" \
22 | 	--debug-mode \
23 | 	--attach-console 
24 | else
25 | echo "🚀 Starting enclave in production mode."
26 | nitro-cli run-enclave \
27 | 	--cpu-count 2 \
28 | 	--memory 3000 \
29 | 	--enclave-cid 4 \
30 | 	--eif-path "$image_eif" 
31 | fi
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "es2015",
 4 |     "lib": ["dom", "dom.iterable", "esnext"],
 5 |     "allowJs": false,
 6 |     "skipLibCheck": true,
 7 |     "esModuleInterop": true,
 8 |     "allowSyntheticDefaultImports": true,
 9 |     "strict": true,
10 |     "forceConsistentCasingInFileNames": true,
11 |     "noFallthroughCasesInSwitch": true,
12 |     "module": "esnext",
13 |     "moduleResolution": "node",
14 |     "resolveJsonModule": true,
15 |     "noEmit": false,
16 |     "jsx": "react",
17 |     "types": ["jest", "node"]
18 | 
19 |   },
20 |   "include": [
21 |     "src/app.tsx"
22 |   ]
23 | }
```

--------------------------------------------------------------------------------
/verifier/wasm/remote-attestation-verifier/remote_attestation_verifier_bg.wasm.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /* tslint:disable */
 2 | /* eslint-disable */
 3 | export const memory: WebAssembly.Memory;
 4 | export const verify_js: (a: number, b: number, c: number, d: number, e: any) => number;
 5 | export const ring_core_0_17_8_bn_mul_mont: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
 6 | export const __wbindgen_malloc: (a: number, b: number) => number;
 7 | export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
 8 | export const __wbindgen_export_2: WebAssembly.Table;
 9 | export const __wbindgen_start: () => void;
10 | 
```

--------------------------------------------------------------------------------
/gvproxy.sh:
--------------------------------------------------------------------------------

```bash
 1 | while true; do
 2 |     sudo pkill -f gvproxy
 3 | 
 4 |     sudo rm -rf /tmp/network.sock
 5 | 
 6 |     sudo /home/ec2-user/trusted-mcp-server/gvisor-tap-vsock/bin/gvproxy -listen vsock://:1024 -listen unix:///tmp/network.sock &
 7 | 
 8 |     sleep 2
 9 | 
10 |     #open port for server
11 |     sudo curl --unix-socket /tmp/network.sock \
12 |         http:/unix/services/forwarder/expose \
13 |         -X POST \
14 |         -d '{"local":":7047","remote":"192.168.127.2:7047"}'
15 | 
16 |     # nitriding ports
17 |     sudo curl --unix-socket /tmp/network.sock \
18 |         http:/unix/services/forwarder/expose \
19 |         -X POST \
20 |         -d '{"local":":443","remote":"192.168.127.2:443"}'
21 | 
22 |     sleep 3000
23 | done
24 | 
```

--------------------------------------------------------------------------------
/verifier/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "baseUrl": ".",
 4 |     "module": "esnext",
 5 |     "target": "es2015",
 6 |     "lib": ["dom", "dom.iterable", "esnext"],
 7 |     "allowJs": true,
 8 |     "skipLibCheck": true,
 9 |     "esModuleInterop": true,
10 |     "allowSyntheticDefaultImports": true,
11 |     "strict": true,
12 |     "forceConsistentCasingInFileNames": true,
13 |     "moduleResolution": "node",
14 |     "resolveJsonModule": true,
15 |     "isolatedModules": true,
16 |     "sourceMap": true,
17 |     "noEmit": true,
18 |     "jsx": "react",
19 |     "paths": {
20 |       "crypto": ["node_modules/crypto-browserify"],
21 |       "stream": ["node_modules/stream-browserify"],
22 |       "vm": ["node_modules/vm-browserify"]
23 |     },
24 |     "types": ["jest", "node"]
25 |   },
26 |   "include": [
27 |     "src"
28 |   ]
29 | }
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/app.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import React, { ReactElement } from 'react';
 2 | import { createRoot } from 'react-dom/client';
 3 | 
 4 | import './app.css';
 5 | import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
 6 | 
 7 | import { VerifyTee } from './components/verify-tee';
 8 | import { VerifyMCP } from './components/verify-mcp';
 9 | 
10 | const container = document.getElementById('root');
11 | const root = createRoot(container!);
12 | 
13 | root.render(<App />);
14 | 
15 | function App(): ReactElement {
16 |   return (
17 |     <Router>
18 |       <div>
19 |         <Routes>
20 |           <Route path="/" element={<VerifyMCP />} />
21 |           <Route path="/verify-tee" element={<VerifyTee />} />
22 |           <Route path="/verify-mcp" element={<VerifyMCP />} />
23 |         </Routes>
24 |       </div>
25 |     </Router>
26 |   );
27 | }
28 | 
```

--------------------------------------------------------------------------------
/verifier/utils/build-tlsn-binaries.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | # Run tlsn Server fixture
 3 | 
 4 | # Set the directory to the location of the script
 5 | cd "$(dirname "$0")"
 6 | 
 7 | # Name of the directory where the repo will be cloned
 8 | REPO_DIR="tlsn"
 9 | 
10 | # Check if the directory exists
11 | if [ ! -d "$REPO_DIR" ]; then
12 |     # Clone the repository if it does not exist
13 |     git clone https://github.com/tlsnotary/tlsn.git "$REPO_DIR"
14 |     cd "$REPO_DIR"
15 | else
16 |     # If the directory exists, just change to it
17 |     cd "$REPO_DIR"
18 |     # Fetch the latest changes in the repo without checkout
19 |     git fetch
20 | fi
21 | 
22 | # Checkout the specific tag
23 | git checkout "v0.1.0-alpha.6"
24 | 
25 | for dir in "tlsn/tlsn-server-fixture/" "notary/server"; do
26 |     # Change to the specific subdirectory
27 |     cd ${dir}
28 | 
29 |     # Build the project
30 |     cargo build --release
31 |     cd -
32 | done
33 | 
```

--------------------------------------------------------------------------------
/verifier/utils/check-wasm.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | 
 3 | DIRECTORY="./wasm/prover/target"
 4 | FORCE_FLAG=0
 5 | 
 6 | # Check if --force or -f flag is passed
 7 | for arg in "$@"
 8 | do
 9 |     if [ "$arg" == "--force" ] || [ "$arg" == "-f" ]
10 |     then
11 |         FORCE_FLAG=1
12 |         break
13 |     fi
14 | done
15 | 
16 | # If force flag is set, remove the directories/files and run the npm command
17 | if [ $FORCE_FLAG -eq 1 ]
18 | then
19 |     echo "Force flag detected, removing directories and files."
20 |     rm -rf ./wasm/prover/pkg
21 |     rm -rf ./wasm/prover/target
22 |     rm -f ./wasm/prover/Cargo.lock
23 |     echo "Running npm run build:wasm"
24 |     npm run build:wasm
25 | # If the directory does not exist or is empty, run the npm command
26 | elif [ ! -d "$DIRECTORY" ] || [ -z "$(ls -A $DIRECTORY)" ]
27 | then
28 |     echo "Running npm run build:wasm"
29 |     npm run build:wasm
30 | else
31 |     echo "$DIRECTORY exists and is not empty."
32 | fi
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | FROM golang:1.23 as builder
 2 | 
 3 | WORKDIR /    
 4 | 
 5 | # Clone the repository and build the stand-alone nitriding executable.
 6 | RUN git clone https://github.com/brave/nitriding-daemon.git
 7 | ARG TARGETARCH
 8 | RUN ARCH=${TARGETARCH} make -C nitriding-daemon/ nitriding
 9 | 
10 | COPY start.sh  /bin/
11 | COPY gmail_mcp /bin/mcp
12 | 
13 | RUN chown root:root /bin/mcp/server.py /bin/start.sh
14 | RUN chmod 0755      /bin/mcp/server.py /bin/start.sh
15 | 
16 | FROM python:3.13-slim-bullseye
17 | RUN apt-get update && apt-get install -y curl git procps && rm -rf /var/lib/apt/lists/*
18 | 
19 | # Copy all our files to the final image.
20 | COPY --from=builder /nitriding-daemon/nitriding /bin/start.sh /bin/
21 | COPY --from=builder /bin/mcp                    /bin/mcp
22 | 
23 | # Install PDM for Python package management
24 | RUN pip install pdm
25 | 
26 | # Install Python dependencies
27 | WORKDIR /bin/mcp
28 | RUN pdm install --no-self --no-editable
29 | 
30 | CMD ["start.sh"]
31 | 
```

--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/sh
 2 | 
 3 | # Create log directory
 4 | mkdir -p /logs
 5 | 
 6 | # Start nitriding with logging
 7 | nitriding -fqdn example.com -ext-pub-port 443 -intport 8080 -appwebsrv http://127.0.0.1:7047 > /logs/nitriding.log 2>&1 &
 8 | NITRIDING_PID=$!
 9 | echo "[sh] Started nitriding with PID $NITRIDING_PID."
10 | 
11 | sleep 1
12 |     
13 | echo "🚀 starting python server"
14 | cd /bin/mcp
15 | pdm run server.py > /logs/server.log 2>&1 &
16 | SERVER_PID=$!
17 | echo "[sh] Python server started with PID $SERVER_PID."
18 | 
19 | # Function to check if a process is running
20 | is_running() {
21 |   ps -p $1 > /dev/null
22 |   return $?
23 | }
24 | 
25 | # Monitor processes and restart if needed
26 | while true; do
27 |   if ! is_running $NITRIDING_PID; then
28 |     echo "[sh] Nitriding process died, restarting..."
29 |     nitriding -fqdn example.com -ext-pub-port 443 -intport 8080 -appwebsrv http://127.0.0.1:7047 > /logs/nitriding.log 2>&1 &
30 |     NITRIDING_PID=$!
31 |     echo "[sh] Restarted nitriding with PID $NITRIDING_PID."
32 |   fi
33 |   
34 |   if ! is_running $SERVER_PID; then
35 |     echo "[sh] Python server died, restarting..."
36 |     cd /bin/new
37 |     pdm run server.py > /logs/server.log 2>&1 &
38 |     SERVER_PID=$!
39 |     echo "[sh] Restarted Python server with PID $SERVER_PID."
40 |   fi
41 |   
42 |   sleep 10
43 | done
44 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "react-ts-webpack",
 3 |   "version": "1.0.0",
 4 |   "description": "",
 5 |   "main": "webpack.js",
 6 |   "scripts": {
 7 |     "dev": "webpack-dev-server --config webpack.js",
 8 |     "build": "webpack --config webpack.js"
 9 |   },
10 |   "author": "",
11 |   "license": "ISC",
12 |   "dependencies": {
13 |     "asn1js": "^3.0.5",
14 |     "class-variance-authority": "^0.7.1",
15 |     "clsx": "^2.1.1",
16 |     "comlink": "^4.4.1",
17 |     "lucide-react": "^0.441.0",
18 |     "react": "^18.2.0",
19 |     "react-dom": "^18.2.0",
20 |     "react-loader-spinner": "^6.1.6",
21 |     "react-router-dom": "^6.26.2",
22 |     "tailwind-merge": "^2.5.2",
23 |     "tee-verifier-js": "../../"
24 |   },
25 |   "devDependencies": {
26 |     "@types/react": "^18.0.26",
27 |     "@types/react-dom": "^18.0.10",
28 |     "autoprefixer": "^10.4.20",
29 |     "babel-loader": "^9.1.3",
30 |     "copy-webpack-plugin": "^11.0.0",
31 |     "crypto-browserify": "^3.12.0",
32 |     "css-loader": "^7.1.2",
33 |     "html-webpack-plugin": "^5.5.0",
34 |     "postcss": "^8.4.47",
35 |     "postcss-loader": "^8.1.1",
36 |     "source-map-loader": "^5.0.0",
37 |     "stream-browserify": "^3.0.0",
38 |     "style-loader": "^4.0.0",
39 |     "tailwindcss": "^3.4.11",
40 |     "ts-loader": "^9.4.2",
41 |     "typescript": "^4.9.4",
42 |     "vm-browserify": "^1.1.2",
43 |     "webpack": "^5.75.0",
44 |     "webpack-cli": "^4.10.0",
45 |     "webpack-dev-server": "^4.11.1"
46 |   }
47 | }
48 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/pkg/snippets/wasm-bindgen-rayon-3e04391371ad0a8e/src/workerHelpers.worker.js:
--------------------------------------------------------------------------------

```javascript
 1 | /*
 2 |  * Copyright 2022 Google Inc. All Rights Reserved.
 3 |  * Licensed under the Apache License, Version 2.0 (the "License");
 4 |  * you may not use this file except in compliance with the License.
 5 |  * You may obtain a copy of the License at
 6 |  *     http://www.apache.org/licenses/LICENSE-2.0
 7 |  * Unless required by applicable law or agreed to in writing, software
 8 |  * distributed under the License is distributed on an "AS IS" BASIS,
 9 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 |  * See the License for the specific language governing permissions and
11 |  * limitations under the License.
12 |  */
13 | 
14 | // Note: our JS should have been generated in
15 | // `[out-dir]/snippets/wasm-bindgen-rayon-[hash]/workerHelpers.worker.js`,
16 | // resolve the main module via `../../..`.
17 | //
18 | // This might need updating if the generated structure changes on wasm-bindgen
19 | // side ever in the future, but works well with bundlers today. The whole
20 | // point of this crate, after all, is to abstract away unstable features
21 | // and temporary bugs so that you don't need to deal with them in your code.
22 | import initWbg, { wbg_rayon_start_worker } from '../../../tlsn_wasm.js';
23 | 
24 | onmessage = async ({ data: { module, memory, receiver } }) => {
25 |   await initWbg(module, memory);
26 |   postMessage(true);
27 |   wbg_rayon_start_worker(receiver);
28 | };
29 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/remote-attestation-verifier/remote_attestation_verifier.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /* tslint:disable */
 2 | /* eslint-disable */
 3 | export function verify_js(attestation_document: Uint8Array, nonce: Uint8Array, pcrs: Array<any>): boolean;
 4 | 
 5 | export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
 6 | 
 7 | export interface InitOutput {
 8 |   readonly memory: WebAssembly.Memory;
 9 |   readonly verify_js: (a: number, b: number, c: number, d: number, e: any) => number;
10 |   readonly ring_core_0_17_8_bn_mul_mont: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
11 |   readonly __wbindgen_malloc: (a: number, b: number) => number;
12 |   readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
13 |   readonly __wbindgen_export_2: WebAssembly.Table;
14 |   readonly __wbindgen_start: () => void;
15 | }
16 | 
17 | export type SyncInitInput = BufferSource | WebAssembly.Module;
18 | /**
19 | * Instantiates the given `module`, which can either be bytes or
20 | * a precompiled `WebAssembly.Module`.
21 | *
22 | * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
23 | *
24 | * @returns {InitOutput}
25 | */
26 | export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
27 | 
28 | /**
29 | * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
30 | * for everything else, calls `WebAssembly.instantiate` directly.
31 | *
32 | * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
33 | *
34 | * @returns {Promise<InitOutput>}
35 | */
36 | export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
37 | 
```

--------------------------------------------------------------------------------
/verifier/webpack.build.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | const webpack = require('webpack');
 2 | const path = require('path');
 3 | const isProd = process.env.NODE_ENV === 'production';
 4 | 
 5 | const envPlugin = new webpack.EnvironmentPlugin({
 6 |   NODE_ENV: 'development',
 7 | });
 8 | 
 9 | const rules = [
10 |   {
11 |     test: /\.tsx?$/,
12 |     exclude: [/(node_modules|.webpack)/],
13 |     rules: [
14 |       {
15 |         loader: 'ts-loader',
16 |         options: {
17 |           configFile: 'tsconfig.json',
18 |           transpileOnly: true,
19 |         },
20 |       },
21 |     ],
22 |   },
23 |   {
24 |     test: /\.node$/,
25 |     use: 'node-loader',
26 |   },
27 | ];
28 | 
29 | var alias = {
30 |   stream: require.resolve('stream-browserify'),
31 |   // crypto: require.resolve('crypto-browserify'),
32 |   // vm: require.resolve('vm-browserify'),
33 | };
34 | 
35 | var fileExtensions = [
36 |   'jpg',
37 |   'jpeg',
38 |   'png',
39 |   'gif',
40 |   'eot',
41 |   'otf',
42 |   'svg',
43 |   'ttf',
44 |   'woff',
45 |   'woff2',
46 | ];
47 | 
48 | module.exports = [
49 |   {
50 |     mode: isProd ? 'production' : 'development',
51 |     entry: {
52 |       lib: path.join(__dirname, 'src', 'lib.ts'),
53 |     },
54 |     target: 'webworker',
55 |     devtool: 'source-map',
56 |     resolve: {
57 |       extensions: ['.ts', '.js'],
58 |     },
59 |     node: {
60 |       __dirname: true,
61 |     },
62 |     module: {
63 |       rules: [...rules],
64 |     },
65 |     output: {
66 |       publicPath: '',
67 |       path: __dirname + '/build',
68 |       filename: `[name].js`,
69 |       libraryTarget: 'umd',
70 |       globalObject: 'this',
71 |       umdNamedDefine: true,
72 |     },
73 |     plugins: [
74 |       envPlugin,
75 |     ],
76 |     resolve: {
77 |       alias: alias,
78 |       extensions: fileExtensions
79 |         .map((extension) => '.' + extension)
80 |         .concat(['.js', '.jsx', '.ts', '.tsx', '.css']),
81 |       fallback: {
82 |         stream: require.resolve('stream-browserify'),
83 |       },
84 |     }
85 |   },
86 | ];
87 | 
```

--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------

```bash
 1 | echo "📦 Setting up nitro instance"
 2 | 
 3 | # Amazon Linux 2023 uses dnf instead of amazon-linux-extras
 4 | echo "📦 Installing Nitro Enclave CLI"
 5 | sudo yum install -y aws-nitro-enclaves-cli aws-nitro-enclaves-cli-devel
 6 | 
 7 | # Create groups if they don't exist
 8 | echo "📦 Setting up user groups"
 9 | sudo groupadd -f ne
10 | sudo groupadd -f docker
11 | 
12 | # Add user to groups
13 | sudo usermod -aG ne ec2-user
14 | sudo usermod -aG docker ec2-user
15 | 
16 | # Install Docker for AL2023
17 | echo "📦 Installing Docker"
18 | sudo yum install -y docker
19 | sudo systemctl enable docker.service
20 | sudo systemctl start docker.service
21 | 
22 | # Setup nitro enclaves service
23 | echo "📦 Setting up Nitro Enclaves service"
24 | sudo yum install -y aws-nitro-enclaves-cli-devel
25 | sudo systemctl enable nitro-enclaves-allocator.service
26 | sudo systemctl start nitro-enclaves-allocator.service
27 | 
28 | # Check if nitro-cli is in path, if not create symlink
29 | if ! command -v nitro-cli &> /dev/null; then
30 |     echo "📦 Setting up nitro-cli command"
31 |     sudo ln -sf /usr/bin/nitro-cli-devel /usr/bin/nitro-cli
32 | fi
33 | 
34 | # Verify nitro-cli installation
35 | nitro-cli --version || echo "nitro-cli not available, may need to log out and back in"
36 | 
37 | echo "📦 Installing development tools"
38 | sudo yum install -y make git
39 | 
40 | echo '📦 Installing Go'
41 | GO_VERSION="1.23.8"  # Keep your original version
42 | wget https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz
43 | sudo rm -rf /usr/local/go
44 | sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz
45 | rm go${GO_VERSION}.linux-amd64.tar.gz
46 | export PATH=$PATH:/usr/local/go/bin
47 | echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
48 | source ~/.bashrc
49 | 
50 | echo '📦 Verify Go version'
51 | go version
52 | 
53 | echo '📦 Installing gvproxy'
54 | git clone https://github.com/containers/gvisor-tap-vsock.git
55 | cd gvisor-tap-vsock
56 | make
57 | 
58 | echo "✅ Setup done, reboot with 'sudo reboot'"
59 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/components/shadcn.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import React from 'react';
 2 | import { cn } from '../utils/misc';
 3 | 
 4 | const Card = React.forwardRef<
 5 |   HTMLDivElement,
 6 |   React.HTMLAttributes<HTMLDivElement>
 7 | >(({ className, ...props }, ref) => (
 8 |   <div
 9 |     ref={ref}
10 |     className={cn(
11 |       'rounded-xl border bg-card text-card-foreground shadow',
12 |       className,
13 |     )}
14 |     {...props}
15 |   />
16 | ));
17 | Card.displayName = 'Card';
18 | 
19 | const CardHeader = React.forwardRef<
20 |   HTMLDivElement,
21 |   React.HTMLAttributes<HTMLDivElement>
22 | >(({ className, ...props }, ref) => (
23 |   <div
24 |     ref={ref}
25 |     className={cn('flex flex-col space-y-1.5 p-6', className)}
26 |     {...props}
27 |   />
28 | ));
29 | CardHeader.displayName = 'CardHeader';
30 | 
31 | const CardTitle = React.forwardRef<
32 |   HTMLParagraphElement,
33 |   React.HTMLAttributes<HTMLHeadingElement>
34 | >(({ className, ...props }, ref) => (
35 |   <h3
36 |     ref={ref}
37 |     className={cn('font-semibold leading-none tracking-tight', className)}
38 |     {...props}
39 |   />
40 | ));
41 | CardTitle.displayName = 'CardTitle';
42 | 
43 | const CardDescription = React.forwardRef<
44 |   HTMLParagraphElement,
45 |   React.HTMLAttributes<HTMLParagraphElement>
46 | >(({ className, ...props }, ref) => (
47 |   <p
48 |     ref={ref}
49 |     className={cn('text-sm text-muted-foreground', className)}
50 |     {...props}
51 |   />
52 | ));
53 | CardDescription.displayName = 'CardDescription';
54 | 
55 | const CardContent = React.forwardRef<
56 |   HTMLDivElement,
57 |   React.HTMLAttributes<HTMLDivElement>
58 | >(({ className, ...props }, ref) => (
59 |   <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
60 | ));
61 | CardContent.displayName = 'CardContent';
62 | 
63 | const CardFooter = React.forwardRef<
64 |   HTMLDivElement,
65 |   React.HTMLAttributes<HTMLDivElement>
66 | >(({ className, ...props }, ref) => (
67 |   <div
68 |     ref={ref}
69 |     className={cn('flex items-center p-6 pt-0', className)}
70 |     {...props}
71 |   />
72 | ));
73 | CardFooter.displayName = 'CardFooter';
74 | 
75 | export {
76 |   Card,
77 |   CardHeader,
78 |   CardFooter,
79 |   CardTitle,
80 |   CardDescription,
81 |   CardContent,
82 | };
83 | 
```

--------------------------------------------------------------------------------
/verifier/test/assets/simple_proof_expected.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |     "serverName": "example.com",
3 |     "time": 1708595467,
4 |     "sent": "GET / HTTP/1.1\r\nhost: example.com\r\naccept: */*\r\naccept-encoding: identity\r\nconnection: close\r\nuser-agent: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n\r\n",
5 |     "recv": "HTTP/1.1 200 OK\r\nAge: 519895\r\nCache-Control: max-age=604800\r\nContent-Type: text/html; charset=UTF-8\r\nDate: Thu, 22 Feb 2024 09:51:08 GMT\r\nEtag: \"3147526947+ident\"\r\nExpires: Thu, 29 Feb 2024 09:51:08 GMT\r\nLast-Modified: Thu, 17 Oct 2019 07:18:26 GMT\r\nServer: ECS (dce/26A0)\r\nVary: Accept-Encoding\r\nX-Cache: HIT\r\nContent-Length: 1256\r\nConnection: close\r\n\r\n<!doctype html>\n<html>\n<head>\n    <title>XXXXXXXXXXXXXX</title>\n\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <style type=\"text/css\">\n    body {\n        background-color: #f0f0f2;\n        margin: 0;\n        padding: 0;\n        font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n        \n    }\n    div {\n        width: 600px;\n        margin: 5em auto;\n        padding: 2em;\n        background-color: #fdfdff;\n        border-radius: 0.5em;\n        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n    }\n    a:link, a:visited {\n        color: #38488f;\n        text-decoration: none;\n    }\n    @media (max-width: 700px) {\n        div {\n            margin: 0 auto;\n            width: auto;\n        }\n    }\n    </style>    \n</head>\n\n<body>\n<div>\n    <h1>XXXXXXXXXXXXXX</h1>\n    <p>This domain is for use in illustrative examples in documents. You may use this\n    domain in literature without prior coordination or asking for permission.</p>\n    <p><a href=\"https://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n",
6 |     "notaryUrl": "http://localhost"
7 | }
```

--------------------------------------------------------------------------------
/verifier/wasm/pkg/snippets/wasm-bindgen-rayon-3e04391371ad0a8e/src/workerHelpers.js:
--------------------------------------------------------------------------------

```javascript
 1 | /*
 2 |  * Copyright 2022 Google Inc. All Rights Reserved.
 3 |  * Licensed under the Apache License, Version 2.0 (the "License");
 4 |  * you may not use this file except in compliance with the License.
 5 |  * You may obtain a copy of the License at
 6 |  *     http://www.apache.org/licenses/LICENSE-2.0
 7 |  * Unless required by applicable law or agreed to in writing, software
 8 |  * distributed under the License is distributed on an "AS IS" BASIS,
 9 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 |  * See the License for the specific language governing permissions and
11 |  * limitations under the License.
12 |  */
13 | 
14 | // Note: this is never used, but necessary to prevent a bug in Firefox
15 | // (https://bugzilla.mozilla.org/show_bug.cgi?id=1702191) where it collects
16 | // Web Workers that have a shared WebAssembly memory with the main thread,
17 | // but are not explicitly rooted via a `Worker` instance.
18 | //
19 | // By storing them in a variable, we can keep `Worker` objects around and
20 | // prevent them from getting GC-d.
21 | let _workers;
22 | 
23 | export async function startWorkers(module, memory, builder) {
24 |   if (builder.numThreads() === 0) {
25 |     throw new Error(`num_threads must be > 0.`);
26 |   }
27 | 
28 |   const workerInit = {
29 |     module,
30 |     memory,
31 |     receiver: builder.receiver()
32 |   };
33 | 
34 |   _workers = await Promise.all(
35 |     Array.from({ length: builder.numThreads() }, async () => {
36 |       // Self-spawn into a new Worker.
37 |       //
38 |       // TODO: while `new URL('...', import.meta.url) becomes a semi-standard
39 |       // way to get asset URLs relative to the module across various bundlers
40 |       // and browser, ideally we should switch to `import.meta.resolve`
41 |       // once it becomes a standard.
42 |       const worker = new Worker(
43 |         new URL('./workerHelpers.worker.js', import.meta.url),
44 |         {
45 |           type: 'module'
46 |         }
47 |       );
48 |       worker.postMessage(workerInit);
49 |       await new Promise(resolve =>
50 |         worker.addEventListener('message', resolve, { once: true })
51 |       );
52 |       return worker;
53 |     })
54 |   );
55 |   builder.build();
56 | }
57 | 
```

--------------------------------------------------------------------------------
/verifier/src/lib.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import initWasm, {
 2 |   initThreadPool,
 3 |   init_logging,
 4 |   LoggingLevel,
 5 |   verify_attestation_document,
 6 |   verify_attestation_signature,
 7 | } from '../wasm/pkg/tlsn_wasm';
 8 | 
 9 | //import { verify_js } from '../wasm/remote-attestation-verifier/remote_attestation_verifier';
10 | 
11 | let LOGGING_LEVEL: LoggingLevel = 'Info';
12 | 
13 | function debug(...args: any[]) {
14 |   if (['Debug', 'Trace'].includes(LOGGING_LEVEL)) {
15 |     console.log('tlsn-js DEBUG', ...args);
16 |   }
17 | }
18 | 
19 | /**
20 |  * Convert the PEM string represetation of a P256 public key to a hex string of its raw bytes
21 |  * @param pemString - The PEM string to convert
22 |  * @returns The raw hex string
23 |  */
24 | export function pemToRawHex(pemString: string) {
25 |   const base64 = pemString
26 |     .replace('-----BEGIN PUBLIC KEY-----', '')
27 |     .replace('-----END PUBLIC KEY-----', '')
28 |     .replace(/\s/g, '');
29 |   return Buffer.from(base64, 'base64').toString('hex').slice(-130);
30 | }
31 | 
32 | /**
33 |  * It generates a random nonce of length 40 using hexadecimal characters.
34 |  * This nonce is used to ensure the uniqueness of the attestation.
35 |  * @returns {string} The generated nonce.
36 |  */
37 | 
38 | export function generateNonce() {
39 |   return Array.from({ length: 40 }, () =>
40 |     Math.floor(Math.random() * 16).toString(16),
41 |   ).join('');
42 | }
43 | 
44 | export { verify_attestation_signature };
45 | 
46 | export async function verify_code_attestation(
47 |   remote_attestation_base64: string,
48 |   expected_nonce: string,
49 |   expected_pcr: string,
50 |   timestamp: number = Math.floor(Date.now() / 1000),
51 | ) {
52 |   return await verify_attestation_document(
53 |     remote_attestation_base64,
54 |     expected_nonce,
55 |     expected_pcr,
56 |     BigInt(timestamp),
57 |   );
58 | }
59 | 
60 | export default async function init(config?: {
61 |   loggingLevel?: LoggingLevel;
62 |   hardwareConcurrency?: number;
63 | }) {
64 |   const {
65 |     loggingLevel = 'Info',
66 |     hardwareConcurrency = navigator.hardwareConcurrency,
67 |   } = config || {};
68 | 
69 |   LOGGING_LEVEL = loggingLevel;
70 | 
71 |   const res = await initWasm();
72 | 
73 |   init_logging({
74 |     level: loggingLevel,
75 |     crate_filters: undefined,
76 |     span_events: undefined,
77 |   });
78 | 
79 |   // 6422528 ~= 6.12 mb
80 |   debug('res.memory=', res.memory);
81 |   debug('res.memory.buffer.length=', res.memory.buffer.byteLength);
82 |   debug('DEBUG', 'initialize thread pool');
83 | 
84 |   await initThreadPool(hardwareConcurrency);
85 |   debug('initialized thread pool');
86 | 
87 |   return true;
88 | }
89 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/components/alert.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | import { cva, type VariantProps } from 'class-variance-authority';
 3 | import { cn } from '../utils/misc';
 4 | import { AlertCircle } from 'lucide-react';
 5 | 
 6 | const alertVariants = cva(
 7 |   'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
 8 |   {
 9 |     variants: {
10 |       variant: {
11 |         default: 'bg-background text-foreground',
12 |         destructive:
13 |           'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
14 |       },
15 |     },
16 |     defaultVariants: {
17 |       variant: 'default',
18 |     },
19 |   },
20 | );
21 | 
22 | const Alert = React.forwardRef<
23 |   HTMLDivElement,
24 |   React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
25 | >(({ className, variant, ...props }, ref) => (
26 |   <div
27 |     ref={ref}
28 |     role="alert"
29 |     className={cn(alertVariants({ variant }), className)}
30 |     {...props}
31 |   />
32 | ));
33 | Alert.displayName = 'Alert';
34 | 
35 | const AlertTitle = React.forwardRef<
36 |   HTMLParagraphElement,
37 |   React.HTMLAttributes<HTMLHeadingElement>
38 | >(({ className, ...props }, ref) => (
39 |   <h5
40 |     ref={ref}
41 |     className={cn('mb-1 font-medium leading-none tracking-tight', className)}
42 |     {...props}
43 |   />
44 | ));
45 | AlertTitle.displayName = 'AlertTitle';
46 | 
47 | const AlertDescription = React.forwardRef<
48 |   HTMLParagraphElement,
49 |   React.HTMLAttributes<HTMLParagraphElement>
50 | >(({ className, ...props }, ref) => (
51 |   <div
52 |     ref={ref}
53 |     className={cn('text-sm [&_p]:leading-relaxed', className)}
54 |     {...props}
55 |   />
56 | ));
57 | AlertDescription.displayName = 'AlertDescription';
58 | 
59 | export { Alert, AlertTitle, AlertDescription };
60 | 
61 | export function CodeHashCallout({ codeHash }: { codeHash: string }) {
62 |   return (
63 |     <Alert>
64 |       <div className="flex items-center gap-2">
65 |         <AlertCircle className="h-4 w-4" />
66 |         <div className="group relative">
67 |           <AlertTitle>Expected Code Hash</AlertTitle>
68 |           <div className="invisible group-hover:visible absolute z-50 w-64 p-2 bg-gray-800 text-white text-sm rounded shadow-lg -top-12 left-0">
69 |             This code hash represents the exact code running in the secure
70 |             enclave
71 |           </div>
72 |         </div>
73 |       </div>
74 |       <AlertDescription>
75 |         <code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
76 |           {codeHash}
77 |         </code>
78 |       </AlertDescription>
79 |     </Alert>
80 |   );
81 | }
82 | 
```

--------------------------------------------------------------------------------
/verifier/webpack.web.dev.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | const webpack = require('webpack');
 2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
 3 | const path = require('path');
 4 | 
 5 | const isProd = process.env.NODE_ENV === 'production';
 6 | 
 7 | const envPlugin = new webpack.EnvironmentPlugin({
 8 |   NODE_ENV: 'development',
 9 |   LOCAL_NOTARY: true,
10 |   LOCAL_WS: false,
11 |   HEADLESS: false,
12 | });
13 | 
14 | const rules = [
15 |   {
16 |     test: /\.node$/,
17 |     use: 'node-loader',
18 |   },
19 |   {
20 |     test: /\.tsx?$/,
21 |     exclude: /(node_modules|.webpack)/,
22 |     use: [
23 |       {
24 |         loader: 'ts-loader',
25 |         options: {
26 |           transpileOnly: true,
27 |         },
28 |       },
29 |     ],
30 |   },
31 | ];
32 | 
33 | const rendererRules = [];
34 | 
35 | module.exports = [
36 |   {
37 |     target: 'web',
38 |     mode: isProd ? 'production' : 'development',
39 |     entry: {
40 |       'full-integration-swapi.spec': path.join(__dirname, 'test', 'specs', 'full-integration-swapi.spec.ts'),
41 |       'simple-verify': path.join(__dirname, 'test', 'specs', 'simple-verify.spec.ts'),
42 |     },
43 |     output: {
44 |       path: __dirname + '/test-build',
45 |       publicPath: '/',
46 |       filename: `[name].js`,
47 |     },
48 |     devtool: 'source-map',
49 |     resolve: {
50 |       extensions: ['.ts', '.tsx', '.js', '.jsx', '.png', '.svg'],
51 |       // modules: [
52 |       //   path.resolve('./node_modules'),
53 |       //   path.resolve(__dirname, compilerOptions.baseUrl),
54 |       // ],
55 |       // fallback: {
56 |       //   browserify: require.resolve('browserify'),
57 |       //   stream: require.resolve('stream-browserify'),
58 |       //   path: require.resolve('path-browserify'),
59 |       //   crypto: require.resolve('crypto-browserify'),
60 |       //   os: require.resolve('os-browserify/browser'),
61 |       //   http: require.resolve('stream-http'),
62 |       //   https: require.resolve('https-browserify'),
63 |       //   assert: require.resolve('assert/'),
64 |       //   events: require.resolve('events/'),
65 |       //   'ansi-html-community': require.resolve('ansi-html-community'),
66 |       //   'html-entities': require.resolve('html-entities'),
67 |       //   constants: false,
68 |       //   fs: false,
69 |       // },
70 |     },
71 |     module: {
72 |       rules: [...rules, ...rendererRules],
73 |     },
74 |     plugins: [
75 |       envPlugin,
76 |       new webpack.ProvidePlugin({
77 |         Buffer: ['buffer', 'Buffer'],
78 |       }),
79 |       new webpack.ProvidePlugin({
80 |         process: 'process',
81 |       }),
82 |       new HtmlWebpackPlugin({
83 |         template: './test/test.ejs',
84 |         filename: `index.html`,
85 |         inject: true,
86 |       }),
87 |     ],
88 |     stats: 'minimal',
89 |     devServer: {
90 |       historyApiFallback: true,
91 |     },
92 |   },
93 | ];
94 | 
```

--------------------------------------------------------------------------------
/verifier/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "tee-verifier-js",
 3 |   "version": "v0.1.2",
 4 |   "description": "JS library for TEE applications",
 5 |   "main": "build/lib.js",
 6 |   "types": "build/lib.d.ts",
 7 |   "files": [
 8 |     "build/",
 9 |     "src/",
10 |     "wasm/pkg/*",
11 |     "readme.md"
12 |   ],
13 |   "scripts": {
14 |     "build:test": "webpack --config webpack.web.dev.config.js",
15 |     "serve:test": "serve  --config ../serve.json ./test-build -l 3001",
16 |     "build:src": "webpack --config webpack.build.config.js",
17 |     "build:types": "tsc --project tsconfig.compile.json",
18 |     "build:tlsn-binaries": "sh utils/build-tlsn-binaries.sh",
19 |     "build:lib": "NODE_ENV=production concurrently npm:build:src npm:build:types",
20 |     "build": "npm run build:lib",
21 |     "update:wasm": "sh utils/check-wasm.sh -f",
22 |     "watch:dev": "webpack --config webpack.web.dev.config.js --watch",
23 |     "predev": "sh utils/check-wasm.sh",
24 |     "dev": "concurrently npm:watch:dev npm:serve:test",
25 |     "lint:eslint": "eslint . --fix",
26 |     "lint:tsc": "tsc --noEmit",
27 |     "lint": "concurrently npm:lint:tsc npm:lint:eslint",
28 |     "run:test": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha -r ts-node/register 'test/testRunner.ts'",
29 |     "test": "npm run build:tlsn-binaries && npm run build:test && npm run run:test",
30 |     "test:only": "npm run build:test && npm run run:test"
31 |   },
32 |   "devDependencies": {
33 |     "@types/expect": "^24.3.0",
34 |     "@types/mocha": "^10.0.6",
35 |     "@types/node": "^22.10.2",
36 |     "@types/serve-handler": "^6.1.4",
37 |     "browserify": "^17.0.0",
38 |     "buffer": "^6.0.3",
39 |     "comlink": "^4.4.1",
40 |     "concurrently": "^5.1.0",
41 |     "constants-browserify": "^1.0.0",
42 |     "copy-webpack-plugin": "^5.0.5",
43 |     "crypto-browserify": "^3.12.0",
44 |     "eslint": "^8.57.0",
45 |     "eslint-config-prettier": "^9.0.0",
46 |     "eslint-plugin-prettier": "^5.0.0",
47 |     "file-loader": "^5.0.2",
48 |     "html-webpack-plugin": "~5.3.2",
49 |     "https-browserify": "^1.0.0",
50 |     "image-webpack-loader": "^6.0.0",
51 |     "js-yaml": "^4.1.0",
52 |     "mocha": "^10.2.0",
53 |     "node-loader": "^0.6.0",
54 |     "prettier": "^3.0.2",
55 |     "process": "^0.11.10",
56 |     "puppeteer": "^21.10.0",
57 |     "serve": "14.2.1",
58 |     "serve-handler": "^6.1.5",
59 |     "stream-browserify": "^3.0.0",
60 |     "ts-loader": "^6.2.1",
61 |     "ts-mocha": "^10.0.0",
62 |     "ts-node": "^10.9.2",
63 |     "typescript": "^4.9.5",
64 |     "typescript-eslint": "^7.4.0",
65 |     "webpack": "^5.75.0",
66 |     "webpack-cli": "^5.0.0",
67 |     "webpack-dev-server": "^4.11.1",
68 |     "webpack-node-externals": "^3.0.0"
69 |   },
70 |   "author": "",
71 |   "license": "ISC",
72 |   "engines": {
73 |     "node": ">= 16.20.2"
74 |   },
75 |   "dependencies": {
76 |     "@types/jest": "^29.5.14"
77 |   }
78 | }
79 | 
```

--------------------------------------------------------------------------------
/verifier/test/specs/full-integration-swapi.spec.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {
 2 |   Prover as _Prover,
 3 |   NotaryServer,
 4 |   NotarizedSession as _NotarizedSession,
 5 |   TlsProof as _TlsProof,
 6 | } from '../../src/lib';
 7 | import { assert } from '../utils';
 8 | import * as Comlink from 'comlink';
 9 | 
10 | const { init, Prover, NotarizedSession, TlsProof }: any = Comlink.wrap(
11 |   // @ts-ignore
12 |   new Worker(new URL('../worker.ts', import.meta.url)),
13 | );
14 | 
15 | (async function () {
16 |   try {
17 |     await init({ loggingLevel: 'Debug' });
18 |     // @ts-ignore
19 |     console.log('test start');
20 |     console.time('prove');
21 |     const prover = (await new Prover({
22 |       id: 'test',
23 |       serverDns: 'swapi.dev',
24 |     })) as _Prover;
25 |     const notary = NotaryServer.from('http://localhost:7047');
26 |     await prover.setup(await notary.sessionUrl());
27 |     await prover.sendRequest('wss://notary.pse.dev/proxy?token=swapi.dev', {
28 |       url: 'https://swapi.dev/api/people/1',
29 |       headers: {
30 |         'content-type': 'application/json',
31 |         secret: 'test_secret',
32 |       },
33 |     });
34 |     const transcript = await prover.transcript();
35 |     console.log({ transcript });
36 |     const commit = {
37 |       sent: [
38 |         ...Object.entries(transcript.ranges.sent.headers)
39 |           .filter(([k]) => k !== 'secret')
40 |           .map(([, v]) => v),
41 |         transcript.ranges.sent.info,
42 |         ...transcript.ranges.sent.lineBreaks,
43 |       ],
44 |       recv: [
45 |         ...Object.entries(transcript.ranges.recv.headers).map(([, v]) => v),
46 |         transcript.ranges.recv.info,
47 |         ...transcript.ranges.recv.lineBreaks,
48 |         transcript.ranges.recv.json!['name'],
49 |         transcript.ranges.recv.json!['hair_color'],
50 |         transcript.ranges.recv.json!['skin_color'],
51 |       ],
52 |     };
53 |     console.log(commit);
54 |     const sessionHex = await prover.notarize(commit);
55 |     const session = (await new NotarizedSession(
56 |       sessionHex,
57 |     )) as _NotarizedSession;
58 |     const proofHex = await session.proof(commit);
59 |     console.log('proof:', proofHex);
60 |     const proof = (await new TlsProof(proofHex)) as _TlsProof;
61 |     console.timeEnd('prove');
62 | 
63 |     console.log('Proof: ', JSON.stringify(proof));
64 | 
65 |     console.time('verify');
66 |     const result = await proof.verify({
67 |       typ: 'P256',
68 |       key: await notary.publicKey(),
69 |     });
70 |     console.timeEnd('verify');
71 | 
72 |     console.log(result);
73 |     assert(result.sent.includes('host: swapi.dev'));
74 |     assert(!result.sent.includes('secret: test_secret'));
75 |     assert(result.recv.includes('"name":"Luke Skywalker"'));
76 |     assert(result.recv.includes('"hair_color":"blond"'));
77 |     assert(result.recv.includes('"skin_color":"fair"'));
78 | 
79 |     // @ts-ignore
80 |     document.getElementById('full-integration-swapi').textContent = 'OK';
81 |   } catch (err) {
82 |     console.log('caught error from wasm');
83 |     console.error(err);
84 | 
85 |     // @ts-ignore
86 |     document.getElementById('full-integration-swapi').textContent = err.message;
87 |   }
88 | })();
89 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/webpack.js:
--------------------------------------------------------------------------------

```javascript
  1 | var webpack = require('webpack'),
  2 |   path = require('path'),
  3 |   CopyWebpackPlugin = require('copy-webpack-plugin'),
  4 |   HtmlWebpackPlugin = require('html-webpack-plugin');
  5 | 
  6 | const ASSET_PATH = process.env.ASSET_PATH || '/';
  7 | 
  8 | var alias = {};
  9 | 
 10 | var fileExtensions = [
 11 |   'jpg',
 12 |   'jpeg',
 13 |   'png',
 14 |   'gif',
 15 |   'eot',
 16 |   'otf',
 17 |   'svg',
 18 |   'ttf',
 19 |   'woff',
 20 |   'woff2',
 21 | ];
 22 | 
 23 | var options = {
 24 |   ignoreWarnings: [
 25 |     /Circular dependency between chunks with runtime/,
 26 |     /ResizeObserver loop completed with undelivered notifications/,
 27 |   ],
 28 |   mode: 'development',
 29 |   entry: {
 30 |     app: path.join(__dirname, 'src', 'app.tsx'),
 31 |   },
 32 |   output: {
 33 |     filename: '[name].bundle.js',
 34 |     path: path.resolve(__dirname, 'build'),
 35 |     clean: true,
 36 |     publicPath: ASSET_PATH,
 37 |   },
 38 |   module: {
 39 |     rules: [
 40 |       {
 41 |         test: /\.css$/,
 42 |         use: ['style-loader', 'css-loader', 'postcss-loader'],
 43 |       },
 44 |       {
 45 |         test: new RegExp('.(' + fileExtensions.join('|') + ')$'),
 46 |         type: 'asset/resource',
 47 |         exclude: /node_modules/,
 48 |       },
 49 |       {
 50 |         test: /\.html$/,
 51 |         loader: 'html-loader',
 52 |         exclude: /node_modules/,
 53 |       },
 54 |       {
 55 |         test: /\.(ts|tsx)$/,
 56 |         exclude: /node_modules/,
 57 |         use: [
 58 |           {
 59 |             loader: 'source-map-loader',
 60 |           },
 61 |           {
 62 |             loader: require.resolve('ts-loader'),
 63 |           },
 64 |         ],
 65 |       },
 66 |       {
 67 |         test: /\.(js|jsx)$/,
 68 |         use: [
 69 |           {
 70 |             loader: 'source-map-loader',
 71 |           },
 72 |           {
 73 |             loader: require.resolve('babel-loader'),
 74 |           },
 75 |         ],
 76 |         exclude: /node_modules/,
 77 |       },
 78 |     ],
 79 |   },
 80 |   resolve: {
 81 |     alias: alias,
 82 |     extensions: fileExtensions
 83 |       .map((extension) => '.' + extension)
 84 |       .concat(['.js', '.jsx', '.ts', '.tsx', '.css']),
 85 |     fallback: {
 86 |       crypto: require.resolve('crypto-browserify'),
 87 |       stream: require.resolve('stream-browserify'),
 88 |       vm: require.resolve('vm-browserify'),
 89 |     },
 90 |   },
 91 |   plugins: [
 92 |     new CopyWebpackPlugin({
 93 |       patterns: [
 94 |         {
 95 |           from: 'node_modules/tee-verifier-js/build',
 96 |           to: path.join(__dirname, 'build'),
 97 |           force: true,
 98 |         },
 99 |       ],
100 |     }),
101 |     new HtmlWebpackPlugin({
102 |       template: path.join(__dirname, 'index.ejs'),
103 |       filename: 'index.html',
104 |       cache: false,
105 |     }),
106 |     new webpack.ProvidePlugin({
107 |       process: 'process/browser',
108 |     }),
109 |     new webpack.ProvidePlugin({
110 |       Buffer: ['buffer', 'Buffer'],
111 |     }),
112 |   ].filter(Boolean),
113 |   // Required by wasm-bindgen-rayon, in order to use SharedArrayBuffer on the Web
114 |   // Ref:
115 |   //  - https://github.com/GoogleChromeLabs/wasm-bindgen-rayon#setting-up
116 |   //  - https://web.dev/i18n/en/coop-coep/
117 |   devServer: {
118 |     headers: {
119 |       'Cross-Origin-Embedder-Policy': 'require-corp',
120 |       'Cross-Origin-Opener-Policy': 'same-origin',
121 |     },
122 |     historyApiFallback: true,
123 |   },
124 | };
125 | 
126 | module.exports = options;
127 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/pkg/tlsn_wasm_bg.wasm.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /* tslint:disable */
 2 | /* eslint-disable */
 3 | export function init_logging(a: number): void;
 4 | export function verify_attestation_document(a: number, b: number, c: number, d: number, e: number, f: number, g: number): number;
 5 | export function verify_attestation_signature(a: number, b: number, c: number, d: number, e: number, f: number, g: number): number;
 6 | export function __wbg_signedsession_free(a: number, b: number): void;
 7 | export function signedsession_serialize(a: number, b: number): void;
 8 | export function signedsession_deserialize(a: number, b: number, c: number): void;
 9 | export function __wbg_prover_free(a: number, b: number): void;
10 | export function prover_new(a: number): number;
11 | export function prover_setup(a: number, b: number, c: number): number;
12 | export function prover_send_request(a: number, b: number, c: number, d: number): number;
13 | export function prover_notarize(a: number): number;
14 | export function __wbg_verifier_free(a: number, b: number): void;
15 | export function verifier_new(a: number): number;
16 | export function verifier_connect(a: number, b: number, c: number): number;
17 | export function verifier_verify(a: number): number;
18 | export function __wbg_wbg_rayon_poolbuilder_free(a: number, b: number): void;
19 | export function wbg_rayon_poolbuilder_numThreads(a: number): number;
20 | export function wbg_rayon_poolbuilder_receiver(a: number): number;
21 | export function wbg_rayon_poolbuilder_build(a: number): void;
22 | export function initThreadPool(a: number): number;
23 | export function wbg_rayon_start_worker(a: number): void;
24 | export function ring_core_0_17_8_bn_mul_mont(a: number, b: number, c: number, d: number, e: number, f: number): void;
25 | export const memory: WebAssembly.Memory;
26 | export function __wbindgen_malloc(a: number, b: number): number;
27 | export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number;
28 | export const __wbindgen_export_3: WebAssembly.Table;
29 | export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h2e88a253da201d98(a: number, b: number, c: number): void;
30 | export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h33fdce4698adb901(a: number, b: number): void;
31 | export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5c02e8a12b71e39b(a: number, b: number, c: number): void;
32 | export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h036d37595979be07(a: number, b: number, c: number): void;
33 | export function __wbindgen_add_to_stack_pointer(a: number): number;
34 | export function __wbindgen_free(a: number, b: number, c: number): void;
35 | export function __wbindgen_exn_store(a: number): void;
36 | export function wasm_bindgen__convert__closures__invoke2_mut__h134b145bfce1dc02(a: number, b: number, c: number, d: number): void;
37 | export function __wbindgen_thread_destroy(a: number, b: number, c: number): void;
38 | export function __wbindgen_start(a: number): void;
39 | 
```

--------------------------------------------------------------------------------
/verifier/src/types.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export type CommitData = {
  2 |   start: number;
  3 |   end: number;
  4 | };
  5 | 
  6 | export type ParsedTranscriptData = {
  7 |   all: CommitData;
  8 |   info: CommitData;
  9 |   headers: { [key: string]: CommitData };
 10 |   body?: CommitData;
 11 |   json?: { [path: string]: CommitData };
 12 |   lineBreaks: CommitData[];
 13 | };
 14 | 
 15 | export type ProofData = {
 16 |   time: number;
 17 |   server_dns: string;
 18 |   sent: string;
 19 |   sent_auth_ranges: { start: number; end: number }[];
 20 |   recv: string;
 21 |   recv_auth_ranges: { start: number; end: number }[];
 22 | };
 23 | 
 24 | export interface AttestationObject {
 25 |   version?: string;
 26 |   meta?: {
 27 |     notaryUrl: string;
 28 |     websocketProxyUrl: string;
 29 |   };
 30 |   signature: string; //signature of the application_data
 31 |   application_data: string; //hex string representation of bytes data
 32 |   application_data_decoded?: DecodedData;
 33 |   attributes: Attribute[]; //attributes extracted from the application_data
 34 | }
 35 | 
 36 | export interface RemoteAttestation {
 37 |   protected: string;
 38 |   payload: string;
 39 |   signature: string;
 40 |   certificate: string;
 41 |   payload_object: Payload;
 42 | }
 43 | export interface Payload {
 44 |   module_id: string;
 45 |   timestamp: number;
 46 |   digest: string;
 47 |   pcrs: Map<number, string>;
 48 |   certificate: Uint8Array;
 49 |   cabundle: Uint8Array[];
 50 |   public_key: Buffer;
 51 |   user_data: Uint8Array | null;
 52 |   nonce: string | null;
 53 | }
 54 | 
 55 | export type Attribute = {
 56 |   attribute_name: string;
 57 |   attribute_hex?: string;
 58 |   signature: string;
 59 | };
 60 | 
 61 | export type DecodedData = {
 62 |   hostname: string;
 63 |   request_url: string;
 64 |   request: string; //contain headers
 65 |   response_header: string;
 66 |   response_body: string;
 67 |   semaphore_identity_commitment: string;
 68 | };
 69 | 
 70 | export type NotaryRequest = {
 71 |   url: string;
 72 |   method: string;
 73 |   headers: Record<string, string>;
 74 |   body?: string;
 75 |   notaryUrl: string;
 76 |   websocketProxyUrl: string;
 77 |   timestamp: number;
 78 | };
 79 | 
 80 | type HttpMethod =
 81 |   | 'GET'
 82 |   | 'POST'
 83 |   | 'PUT'
 84 |   | 'DELETE'
 85 |   | 'HEAD'
 86 |   | 'OPTIONS'
 87 |   | 'PATCH';
 88 | type ResponseType = 'json' | 'text' | 'xml' | 'html';
 89 | 
 90 | export interface Provider {
 91 |   id: number;
 92 |   host: string; // e.g. api.x.com
 93 |   title: string;
 94 |   description: string;
 95 |   icon: string; //url to icon image
 96 | 
 97 |   urlRegex: string; // e.g. ^https://api\.x\.com/1\.1/account/settings\.json(\?.*)?$
 98 |   targetUrl: string; // URL to redirect user before notarization. e.g. https://www.x.com/home
 99 |   method: HttpMethod; // e.g. GET
100 |   responseType: ResponseType;
101 | 
102 |   actionSelectors?: string[]; // url to redirect user before notarization. e.g. ["a[href^='/user/'][href$='/']"] or ["https://www.x.com/home"]
103 |   preprocessor?: string; // Javascript function to process the response in a form that is more easy to evaluate. e.g. "function(data) { var result = ''; for (var key in data) { result += key + '=' + data[key] + '; '; } return JSON.parse(result); }"
104 |   attributes?: string[]; // List of JMESPath expressions used to extract attributes from the provider's response.  e.g. ["screen_name"]
105 | }
106 | 
107 | interface ExpectedPcrs {
108 |   [key: string]: string; // Base64-encoded PCR value
109 | }
110 | 
111 | export interface NotaryConfig {
112 |   version: string;
113 |   EXPECTED_PCRS: ExpectedPcrs;
114 |   PROVIDERS: Provider[];
115 |   [key: string]: any; // For additional properties
116 | }
117 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/components/verify-tee.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React, { ReactElement, useEffect, useState } from 'react';
  2 | import { CheckCircle, RefreshCw, XCircle } from 'lucide-react';
  3 | // import { Link } from 'react-router-dom';
  4 | import * as Comlink from 'comlink';
  5 | 
  6 | const { init, verify_code_attestation }: any = Comlink.wrap(
  7 |   new Worker(new URL('../utils/worker.ts', import.meta.url)),
  8 | );
  9 | 
 10 | const nonce = '0000000000000000000000000000000000000000';
 11 | 
 12 | const EXPECTED_PCRS = {
 13 |   '1': 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
 14 |   '2': 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
 15 | };
 16 | 
 17 | export function VerifyTee(): ReactElement {
 18 |   const [processingVerification, setProcessingVerification] = useState(false);
 19 | 
 20 |   const [resultVerify, setResultVerify] = useState<boolean | null>(null);
 21 | 
 22 |   const [codeAttestation, setCodeAttestation] = useState<null | string>('');
 23 |   const [error, setError] = useState<null | string>(null);
 24 | 
 25 |   const verify_attestation_document = async () => {
 26 |     if (!codeAttestation) {
 27 |       setError('Please enter a valid code attestation');
 28 |       return;
 29 |     }
 30 |     const codeAttestation_ = codeAttestation.replace(/\\n/g, '').trim();
 31 | 
 32 |     console.log('codeAttestation_', codeAttestation_);
 33 |     setProcessingVerification(true);
 34 |     try {
 35 |       const resultVerify = await verify_code_attestation(
 36 |         codeAttestation_,
 37 |         nonce,
 38 |         EXPECTED_PCRS,
 39 |         Math.floor(Date.now() / 1000),
 40 |       );
 41 | 
 42 |       setResultVerify(resultVerify);
 43 |     } catch (e) {
 44 |       setResultVerify(false);
 45 |       setError((e as Error).message);
 46 |     } finally {
 47 |       setProcessingVerification(false);
 48 |     }
 49 |   };
 50 |   useEffect(() => {
 51 |     const initialize = async () => {
 52 |       await init({ loggingLevel: 'Debug' });
 53 |     };
 54 | 
 55 |     initialize();
 56 |   }, []);
 57 | 
 58 |   return (
 59 |     <div>
 60 |       <div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
 61 |         <div className="flex justify-between items-center mb-4"></div>
 62 | 
 63 |         <div className="mt-2 h-30 overflow-y-auto border border-gray-200 rounded p-4 mb-4">
 64 |           <h2 className="text-l font-bold">
 65 |             {' '}
 66 |             1) Get your code attestation from enclave
 67 |           </h2>
 68 | 
 69 |           <h2 className="text-l font-bold">
 70 |             {' '}
 71 |             2) Paste code attestation in base64 format
 72 |           </h2>
 73 | 
 74 |           <textarea
 75 |             id="nonce"
 76 |             name="nonce"
 77 |             className="mt-1 block w-96 h-32 overflow-y-auto rounded-md border border-gray-300 shadow-sm focus:border-green-500 focus:ring-green-500 sm:text-sm"
 78 |             placeholder={codeAttestation ?? ''}
 79 |             onChange={(e) => setCodeAttestation(e.target.value)}
 80 |           />
 81 |         </div>
 82 | 
 83 |         <div className="p-8">
 84 |           <div className="flex justify-between items-center mb-4">
 85 |             <button
 86 |               onClick={verify_attestation_document}
 87 |               disabled={processingVerification}
 88 |               className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed flex items-center"
 89 |             >
 90 |               {processingVerification ? (
 91 |                 <>
 92 |                   <RefreshCw className="animate-spin -ml-1 mr-2 h-5 w-5" />
 93 |                   Verifying...
 94 |                 </>
 95 |               ) : (
 96 |                 <>
 97 |                   <CheckCircle className="mr-2 h-5 w-5" />
 98 |                   Verify Remote Attestation
 99 |                 </>
100 |               )}
101 |             </button>
102 |           </div>
103 | 
104 |           {resultVerify !== null && (
105 |             <div
106 |               className={`mt-4 p-4 rounded-md ${resultVerify ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`}
107 |             >
108 |               <div className="flex items-center">
109 |                 {resultVerify ? (
110 |                   <CheckCircle className="h-5 w-5 mr-2" />
111 |                 ) : (
112 |                   <XCircle className="h-5 w-5 mr-2" />
113 |                 )}
114 |                 <span className="font-medium">
115 |                   {resultVerify
116 |                     ? 'Remote attestation is valid'
117 |                     : 'Remote attestation is invalid'}
118 |                   {!resultVerify && <p>{error}</p>}
119 |                 </span>
120 |               </div>
121 |             </div>
122 |           )}
123 |         </div>
124 |       </div>
125 |     </div>
126 |   );
127 | }
128 | 
```

--------------------------------------------------------------------------------
/verifier/test/testRunner.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import puppeteer, { Browser, Page, PuppeteerLaunchOptions } from 'puppeteer';
  2 | import { describe, it, before, after } from 'mocha';
  3 | const assert = require('assert');
  4 | import { exec, ChildProcess } from 'node:child_process';
  5 | import * as fs from 'fs';
  6 | import path from 'path';
  7 | const yaml = require('js-yaml');
  8 | 
  9 | const timeout = 300000;
 10 | 
 11 | // puppeteer options
 12 | let opts: PuppeteerLaunchOptions = {
 13 |   headless: !!process.env.HEADLESS ? 'new' : false,
 14 |   slowMo: 100,
 15 |   timeout: timeout,
 16 | };
 17 | 
 18 | if (process.env.CHROME_PATH) {
 19 |   opts = {
 20 |     ...opts,
 21 |     executablePath: process.env.CHROME_PATH,
 22 |   };
 23 | }
 24 | 
 25 | let browser: Browser;
 26 | let page: Page;
 27 | let server: ChildProcess;
 28 | 
 29 | let tlsnServerFixture: ChildProcess;
 30 | const spawnTlsnServerFixture = () => {
 31 |   const tlsnServerFixturePath = './utils/tlsn/tlsn/tlsn-server-fixture/';
 32 |   // Spawn the server process
 33 |   // tlsnServerFixture = spawn(tlsnServerFixturePath, []);
 34 |   tlsnServerFixture = exec(`../target/release/main`, {
 35 |     cwd: tlsnServerFixturePath,
 36 |   });
 37 | 
 38 |   tlsnServerFixture.stdout?.on('data', (data) => {
 39 |     console.log(`Server: ${data}`);
 40 |   });
 41 | 
 42 |   tlsnServerFixture.stderr?.on('data', (data) => {
 43 |     console.error(`Server Error: ${data}`);
 44 |   });
 45 | };
 46 | 
 47 | let localNotaryServer: ChildProcess;
 48 | const spawnLocalNotaryServer = async () => {
 49 |   const localNotaryServerPath = './utils/tlsn/notary/server';
 50 |   localNotaryServer = exec(`../target/release/notary-server`, {
 51 |     cwd: localNotaryServerPath,
 52 |   });
 53 |   localNotaryServer.stdout?.on('data', (data) => {
 54 |     console.log(`Server: ${data}`);
 55 |   });
 56 | 
 57 |   localNotaryServer.stderr?.on('data', (data) => {
 58 |     console.error(`Server Error: ${data}`);
 59 |   });
 60 | 
 61 |   // wait for the notary server to be ready
 62 |   while (true) {
 63 |     try {
 64 |       const response = await fetch('http://127.0.0.1:7047/info');
 65 |       if (response.ok) {
 66 |         return;
 67 |       }
 68 |     } catch (error) {
 69 |       console.error('Waiting for local notary server...', error);
 70 |     }
 71 |     await new Promise((resolve) => setTimeout(resolve, 1000));
 72 |   }
 73 | };
 74 | 
 75 | const configureNotarySerer = () => {
 76 |   try {
 77 |     const configPath = './utils/tlsn/notary/server/config/config.yaml';
 78 |     const fileContents = fs.readFileSync(configPath, 'utf8');
 79 |     const data = yaml.load(fileContents) as any;
 80 |     data.tls.enabled = false;
 81 |     data.server.host = '127.0.0.1';
 82 |     const newYaml = yaml.dump(data);
 83 |     fs.writeFileSync(configPath, newYaml, 'utf8');
 84 |     console.log('YAML file has been updated.');
 85 |   } catch (error) {
 86 |     console.error('Error reading or updating the YAML file:', error);
 87 |   }
 88 | };
 89 | 
 90 | // expose variables
 91 | before(async function () {
 92 |   server = exec('serve  --config ../serve.json ./test-build -l 3001');
 93 | 
 94 |   spawnTlsnServerFixture();
 95 |   configureNotarySerer();
 96 |   await spawnLocalNotaryServer();
 97 |   browser = await puppeteer.launch(opts);
 98 |   page = await browser.newPage();
 99 |   await page.goto('http://127.0.0.1:3001');
100 | });
101 | 
102 | // close browser and reset global variables
103 | after(async function () {
104 |   console.log('Cleaning up:');
105 | 
106 |   try {
107 |     tlsnServerFixture.kill();
108 |     console.log('* Stopped TLSN Server Fixture ✅');
109 | 
110 |     localNotaryServer.kill();
111 |     console.log('* Stopped Notary Server ✅');
112 | 
113 |     server.kill();
114 |     console.log('* Stopped Test Web Server ✅');
115 | 
116 |     await page.close();
117 |     await browser.close();
118 |     const childProcess = browser.process();
119 |     if (childProcess) {
120 |       childProcess.kill(9);
121 |     }
122 |     console.log('* Closed browser ✅');
123 |     process.exit(0);
124 |   } catch (e) {
125 |     console.error(e);
126 |     process.exit(0);
127 |   }
128 | });
129 | 
130 | describe('tlsn-js test suite', function () {
131 |   fs.readdirSync(path.join(__dirname, 'specs')).forEach((file) => {
132 |     const [id] = file.split('.');
133 |     it(`Test ID: ${id}`, async function () {
134 |       const content = await check(id);
135 |       assert(content === 'OK');
136 |     });
137 |   });
138 |   // it('should prove and verify data from the local tlsn-server-fixture', async function () {
139 |   //   const content = await check('full-integration-swapi');
140 |   //   assert(content === 'OK');
141 |   // });
142 |   //
143 |   // it('should verify', async function () {
144 |   //   const content = await check('simple-verify');
145 |   //   assert(content === 'OK');
146 |   // });
147 | });
148 | 
149 | async function check(testId: string): Promise<string> {
150 |   const startTime = Date.now();
151 |   const attemptFetchContent = async (): Promise<string> => {
152 |     const content = await page.$eval(
153 |       `#${testId}`,
154 |       (el: any) => el.textContent || '',
155 |     );
156 |     if (content) return content;
157 |     const elapsedTime = Date.now() - startTime;
158 |     if (elapsedTime >= timeout) {
159 |       throw new Error(
160 |         `Timeout: Failed to retrieve content for '#${testId}' within ${timeout} ms.`,
161 |       );
162 |     }
163 |     await new Promise((resolve) => setTimeout(resolve, 1000));
164 |     return attemptFetchContent();
165 |   };
166 |   return attemptFetchContent();
167 | }
168 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/utils/requests.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export interface RequestConfig {
  2 |   dns: string;
  3 |   url: string;
  4 |   method: string;
  5 |   headers: Record<string, string>;
  6 |   body?: any;
  7 | }
  8 | 
  9 | export const requests: Record<string, RequestConfig> = {
 10 |   dummy: {
 11 |     dns: 'dummyjson.com',
 12 |     url: 'https://dummyjson.com/products/1',
 13 |     method: 'GET',
 14 |     headers: {
 15 |       'Content-Type': 'application/json',
 16 |     },
 17 |     body: {
 18 |       hello: 'world',
 19 |       one: 1,
 20 |     },
 21 |   },
 22 |   swapi: {
 23 |     dns: 'swapi.dev',
 24 |     url: 'https://swapi.dev/api/people/1',
 25 |     method: 'GET',
 26 |     headers: {
 27 |       'Content-Type': 'application/json',
 28 |     },
 29 |     body: {
 30 |       hello: 'world',
 31 |       one: 1,
 32 |     },
 33 |   },
 34 |   twitter_profile: {
 35 |     dns: 'api.x.com',
 36 |     url: 'https://api.x.com/1.1/account/settings.json?include_ext_sharing_audiospaces_listening_data_with_followers=true&include_mention_filter=true&include_nsfw_user_flag=true&include_nsfw_admin_flag=true&include_ranked_timeline=true&include_alt_text_compose=true&ext=ssoConnections&include_country_code=true&include_ext_dm_nsfw_media_filter=true',
 37 |     method: 'GET',
 38 |     headers: {
 39 |       accept: '*/*',
 40 |       'accept-language':
 41 |         'en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-FR;q=0.6,zh-FR;q=0.5,zh;q=0.4,ar-FR;q=0.3,ar;q=0.2',
 42 |       authorization:
 43 |         'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
 44 |       cookie: '',
 45 |       dnt: '1',
 46 |       origin: 'https://x.com',
 47 |       priority: 'u=1, i',
 48 |       referer: 'https://x.com/',
 49 |       'sec-ch-ua':
 50 |         '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
 51 |       'sec-ch-ua-mobile': '?0',
 52 |       'sec-ch-ua-platform': '"Linux"',
 53 |       'sec-fetch-dest': 'empty',
 54 |       'sec-fetch-mode': 'cors',
 55 |       'sec-fetch-site': 'same-site',
 56 |       'user-agent':
 57 |         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
 58 |       'x-client-transaction-id':
 59 |         '8bJcp2Wc6qg55CwNDbI1860M+C+hQh8BSxeSXvDbxWtpItZN8w589MSRhPa8j5Pe72PhnvPcCfkcKomHIJbPnoc1A2j48g',
 60 |       'x-csrf-token':
 61 |         '973e0be66e4b49591fb2475c8fb92ca0943b738898faa61276c31357ed3094b02eda226fb52e2166236683bcd046ce089be090e0ee3bf50f8272f12a3a47f8ec63199b024583f5e49a64a4f618ba28be',
 62 |       'x-twitter-active-user': 'yes',
 63 |       'x-twitter-auth-type': 'OAuth2Session',
 64 |       'x-twitter-client-language': 'en',
 65 |     },
 66 |   },
 67 |   twitter_login: {
 68 |     dns: 'api.x.com',
 69 |     url: 'https://api.x.com/1.1/help/settings.json?include_zero_rate=true&feature_set_token=c34254773736d750fd311352b336708862ecf6d6&settings_version=7fada87ecd68d5b2e904cbf5d7dad752',
 70 |     method: 'GET',
 71 |     headers: {
 72 |       accept: '*/*',
 73 |       'accept-language':
 74 |         'en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-FR;q=0.6,zh-FR;q=0.5,zh;q=0.4,ar-FR;q=0.3,ar;q=0.2',
 75 |       authorization:
 76 |         'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
 77 |       cookie: '',
 78 |       dnt: '1',
 79 |       origin: 'https://x.com',
 80 |       priority: 'u=1, i',
 81 |       referer: 'https://x.com/',
 82 |       'sec-ch-ua':
 83 |         '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
 84 |       'sec-ch-ua-mobile': '?0',
 85 |       'sec-ch-ua-platform': '"Linux"',
 86 |       'sec-fetch-dest': 'empty',
 87 |       'sec-fetch-mode': 'cors',
 88 |       'sec-fetch-site': 'same-site',
 89 |       'user-agent':
 90 |         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
 91 |       'x-client-transaction-id':
 92 |         'zdz5xWCz5kUuKembq56wZi8a0WR8kEj4b975TbzD/BImMwSyw5xxDR0IQxEGh43hRA/eos8169huHc8zBNpDQ3qqZOZgzg',
 93 |       'x-csrf-token':
 94 |         '8ba1514a1bfc0528522f6bd38edbf9203af724e0dfb628c178c331ed82ee45d70e7bd0eeeff10bfed2d8c991fa0008702369febe127a2a08067ba59d56a6f5fabb108c97469c65587d360da1bc7382d3',
 95 |       'x-twitter-active-user': 'yes',
 96 |       'x-twitter-auth-type': 'OAuth2Session',
 97 |       'x-twitter-client-language': 'en',
 98 |     },
 99 |   },
100 |   wise_balance: {
101 |     dns: 'wise.com',
102 |     url: 'https://wise.com/gateway/v4/profiles/39893034/balances?types=STANDARD,SAVINGS',
103 |     method: 'GET',
104 |     headers: {
105 |       accept: 'application/json, text/plain, */*',
106 |       'accept-language': 'en-US',
107 |       cookie: '',
108 |       dnt: '1',
109 |       priority: 'u=1, i',
110 |       referer: 'https://wise.com/home',
111 |       'sec-ch-ua':
112 |         '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
113 |       'sec-ch-ua-arch': '"x86"',
114 |       'sec-ch-ua-bitness': '"64"',
115 |       'sec-ch-ua-mobile': '?0',
116 |       'sec-ch-ua-model': '""',
117 |       'sec-ch-ua-platform': '"Linux"',
118 |       'sec-ch-ua-platform-version': '"6.8.0"',
119 |       'sec-fetch-dest': 'empty',
120 |       'sec-fetch-mode': 'cors',
121 |       'sec-fetch-site': 'same-origin',
122 |       'user-agent':
123 |         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
124 |       'x-access-token': 'Tr4n5f3rw153',
125 |       'x-visual-context': 'personal::light',
126 |     },
127 |   },
128 |   ameli_login: {
129 |     dns: 'assure.ameli.fr',
130 |     url: 'https://assure.ameli.fr/PortailAS/appmanager/PortailAS/assure?_nfpb=true&_pageLabel=as_login_page&connexioncompte_2actionEvt=connecter',
131 |     method: 'GET',
132 |     headers: {
133 |       Accept:
134 |         'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
135 |       'Accept-Language':
136 |         'en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-FR;q=0.6,zh-FR;q=0.5,zh;q=0.4,ar-FR;q=0.3,ar;q=0.2',
137 |       'Cache-Control': 'max-age=0',
138 |       Connection: 'keep-alive',
139 |       Cookie: '',
140 |       DNT: '1',
141 |       Referer: 'https://ameliconnect.ameli.fr/',
142 |       'Sec-Fetch-Dest': 'document',
143 |       'Sec-Fetch-Mode': 'navigate',
144 |       'Sec-Fetch-Site': 'same-site',
145 |       'Sec-Fetch-User': '?1',
146 |       'Upgrade-Insecure-Requests': '1',
147 |       'User-Agent':
148 |         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
149 |       'sec-ch-ua':
150 |         '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
151 |       'sec-ch-ua-mobile': '?0',
152 |       'sec-ch-ua-platform': '"Linux"',
153 |     },
154 |   },
155 |   linkedin_feed: {
156 |     dns: 'www.linkedin.com',
157 |     url: 'https://www.linkedin.com/feed/',
158 |     method: 'GET',
159 |     headers: {
160 |       Accept:
161 |         'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
162 |       'Accept-Language':
163 |         'en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-FR;q=0.6,zh-FR;q=0.5,zh;q=0.4,ar-FR;q=0.3,ar;q=0.2',
164 |       'Cache-Control': 'max-age=0',
165 |       Connection: 'keep-alive',
166 |       Cookie: '',
167 |       DNT: '1',
168 |       Priority: 'u=0, i',
169 |       Referer: 'https://www.linkedin.com/checkpoint/lg/login-submit',
170 |       'Sec-CH-UA':
171 |         '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
172 |       'Sec-CH-UA-Mobile': '?0',
173 |       'Sec-CH-UA-Platform': '"Linux"',
174 |       'Sec-Fetch-Dest': 'document',
175 |       'Sec-Fetch-Mode': 'navigate',
176 |       'Sec-Fetch-Site': 'same-origin',
177 |       'Sec-Fetch-User': '?1',
178 |       'Upgrade-Insecure-Requests': '1',
179 |       'User-Agent':
180 |         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
181 |     },
182 |   },
183 | 
184 |   google_personal_info: {
185 |     dns: 'myaccount.google.com',
186 |     url: 'https://myaccount.google.com/personal-info?hl=fr&utm_source=OGB&utm_medium=act',
187 |     method: 'GET',
188 |     headers: {
189 |       Accept:
190 |         'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
191 |       'Accept-Language': 'en-US,en;q=0.9',
192 |       'Cache-Control': 'max-age=0',
193 |       Cookie: '',
194 |       DNT: '1',
195 |       Priority: 'u=0, i',
196 |       'Sec-CH-UA':
197 |         '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
198 |       'Sec-CH-UA-Arch': '"x86"',
199 |       'Sec-CH-UA-Bitness': '"64"',
200 |       'Sec-CH-UA-Form-Factors': '"Desktop"',
201 |       'Sec-CH-UA-Full-Version': '"127.0.6533.119"',
202 |       'Sec-CH-UA-Full-Version-List':
203 |         '"Not)A;Brand";v="99.0.0.0", "Google Chrome";v="127.0.6533.119", "Chromium";v="127.0.6533.119"',
204 |       'Sec-CH-UA-Mobile': '?0',
205 |       'Sec-CH-UA-Model': '""',
206 |       'Sec-CH-UA-Platform': '"Linux"',
207 |       'Sec-CH-UA-Platform-Version': '"6.8.0"',
208 |       'Sec-CH-UA-Wow64': '?0',
209 |       'Sec-Fetch-Dest': 'document',
210 |       'Sec-Fetch-Mode': 'navigate',
211 |       'Sec-Fetch-Site': 'same-origin',
212 |       'Sec-Fetch-User': '?1',
213 |       'Upgrade-Insecure-Requests': '1',
214 |       'User-Agent':
215 |         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
216 |     },
217 |   },
218 | };
219 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/pkg/tlsn_wasm.d.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /* tslint:disable */
  2 | /* eslint-disable */
  3 | /**
  4 | * Initializes logging.
  5 | * @param {LoggingConfig | undefined} [config]
  6 | */
  7 | export function init_logging(config?: LoggingConfig): void;
  8 | /**
  9 | * @param {string} attestation_document
 10 | * @param {string} nonce_expected
 11 | * @param {string} pcr_expected
 12 | * @param {bigint} timestamp
 13 | * @returns {boolean}
 14 | */
 15 | export function verify_attestation_document(attestation_document: string, nonce_expected: string, pcr_expected: string, timestamp: bigint): boolean;
 16 | /**
 17 | * @param {string} hex_application_data
 18 | * @param {string} hex_raw_signature
 19 | * @param {string} hex_raw_public_key
 20 | * @param {boolean} hash_appdata
 21 | * @returns {boolean}
 22 | */
 23 | export function verify_attestation_signature(hex_application_data: string, hex_raw_signature: string, hex_raw_public_key: string, hash_appdata: boolean): boolean;
 24 | /**
 25 | * @param {number} num_threads
 26 | * @returns {Promise<any>}
 27 | */
 28 | export function initThreadPool(num_threads: number): Promise<any>;
 29 | /**
 30 | * @param {number} receiver
 31 | */
 32 | export function wbg_rayon_start_worker(receiver: number): void;
 33 | export interface AttestationDocument {
 34 |     protected: string | undefined;
 35 |     signature: string | undefined;
 36 |     payload: string | undefined;
 37 |     certificate: string | undefined;
 38 | }
 39 | 
 40 | export type Body = JsonValue;
 41 | 
 42 | export type Method = "GET" | "POST" | "PUT" | "DELETE";
 43 | 
 44 | export interface HttpRequest {
 45 |     uri: string;
 46 |     method: Method;
 47 |     headers: Map<string, number[]>;
 48 |     body: Body | undefined;
 49 | }
 50 | 
 51 | export interface HttpResponse {
 52 |     status: number;
 53 |     headers: [string, number[]][];
 54 |     body: string;
 55 | }
 56 | 
 57 | export interface Transcript {
 58 |     sent: number[];
 59 |     recv: number[];
 60 | }
 61 | 
 62 | export interface Commit {
 63 |     sent: { start: number; end: number }[];
 64 |     recv: { start: number; end: number }[];
 65 | }
 66 | 
 67 | export interface Reveal {
 68 |     sent: { start: number; end: number }[];
 69 |     recv: { start: number; end: number }[];
 70 | }
 71 | 
 72 | export interface VerifierData {
 73 |     server_dns: string;
 74 |     sent: number[];
 75 |     sent_auth_ranges: { start: number; end: number }[];
 76 |     received: number[];
 77 |     received_auth_ranges: { start: number; end: number }[];
 78 | }
 79 | 
 80 | export interface ProverConfig {
 81 |     id: string;
 82 |     server_dns: string;
 83 |     max_sent_data: number | undefined;
 84 |     max_recv_data: number | undefined;
 85 | }
 86 | 
 87 | export interface VerifierConfig {
 88 |     id: string;
 89 |     max_sent_data: number | undefined;
 90 |     max_received_data: number | undefined;
 91 | }
 92 | 
 93 | export interface CrateLogFilter {
 94 |     level: LoggingLevel;
 95 |     name: string;
 96 | }
 97 | 
 98 | export interface LoggingConfig {
 99 |     level: LoggingLevel | undefined;
100 |     crate_filters: CrateLogFilter[] | undefined;
101 |     span_events: SpanEvent[] | undefined;
102 | }
103 | 
104 | export type SpanEvent = "New" | "Close" | "Active";
105 | 
106 | export type LoggingLevel = "Trace" | "Debug" | "Info" | "Warn" | "Error";
107 | 
108 | /**
109 | */
110 | export class Prover {
111 |   free(): void;
112 | /**
113 | * @param {ProverConfig} config
114 | */
115 |   constructor(config: ProverConfig);
116 | /**
117 | * Set up the prover.
118 | *
119 | * This performs all Tee setup prior to establishing the connection to the
120 | * application server.
121 | * @param {string} verifier_url
122 | * @returns {Promise<void>}
123 | */
124 |   setup(verifier_url: string): Promise<void>;
125 | /**
126 | * Send the HTTP request to the server.
127 | * @param {string} ws_proxy_url
128 | * @param {HttpRequest} request
129 | * @returns {Promise<HttpResponse>}
130 | */
131 |   send_request(ws_proxy_url: string, request: HttpRequest): Promise<HttpResponse>;
132 | /**
133 | * Runs the notarization protocol.
134 | * @returns {Promise<string>}
135 | */
136 |   notarize(): Promise<string>;
137 | }
138 | /**
139 | */
140 | export class SignedSession {
141 |   free(): void;
142 | /**
143 | * Serializes to a byte array.
144 | * @returns {Uint8Array}
145 | */
146 |   serialize(): Uint8Array;
147 | /**
148 | * Deserializes from a byte array.
149 | * @param {Uint8Array} bytes
150 | * @returns {SignedSession}
151 | */
152 |   static deserialize(bytes: Uint8Array): SignedSession;
153 | }
154 | /**
155 | */
156 | export class Verifier {
157 |   free(): void;
158 | /**
159 | * @param {VerifierConfig} config
160 | */
161 |   constructor(config: VerifierConfig);
162 | /**
163 | * Connect to the prover.
164 | * @param {string} prover_url
165 | * @returns {Promise<void>}
166 | */
167 |   connect(prover_url: string): Promise<void>;
168 | /**
169 | * Verifies the connection and finalizes the protocol.
170 | * @returns {Promise<void>}
171 | */
172 |   verify(): Promise<void>;
173 | }
174 | /**
175 | */
176 | export class wbg_rayon_PoolBuilder {
177 |   free(): void;
178 | /**
179 | * @returns {number}
180 | */
181 |   numThreads(): number;
182 | /**
183 | * @returns {number}
184 | */
185 |   receiver(): number;
186 | /**
187 | */
188 |   build(): void;
189 | }
190 | 
191 | export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
192 | 
193 | export interface InitOutput {
194 |   readonly init_logging: (a: number) => void;
195 |   readonly verify_attestation_document: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number;
196 |   readonly verify_attestation_signature: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number;
197 |   readonly __wbg_signedsession_free: (a: number, b: number) => void;
198 |   readonly signedsession_serialize: (a: number, b: number) => void;
199 |   readonly signedsession_deserialize: (a: number, b: number, c: number) => void;
200 |   readonly __wbg_prover_free: (a: number, b: number) => void;
201 |   readonly prover_new: (a: number) => number;
202 |   readonly prover_setup: (a: number, b: number, c: number) => number;
203 |   readonly prover_send_request: (a: number, b: number, c: number, d: number) => number;
204 |   readonly prover_notarize: (a: number) => number;
205 |   readonly __wbg_verifier_free: (a: number, b: number) => void;
206 |   readonly verifier_new: (a: number) => number;
207 |   readonly verifier_connect: (a: number, b: number, c: number) => number;
208 |   readonly verifier_verify: (a: number) => number;
209 |   readonly __wbg_wbg_rayon_poolbuilder_free: (a: number, b: number) => void;
210 |   readonly wbg_rayon_poolbuilder_numThreads: (a: number) => number;
211 |   readonly wbg_rayon_poolbuilder_receiver: (a: number) => number;
212 |   readonly wbg_rayon_poolbuilder_build: (a: number) => void;
213 |   readonly initThreadPool: (a: number) => number;
214 |   readonly wbg_rayon_start_worker: (a: number) => void;
215 |   readonly ring_core_0_17_8_bn_mul_mont: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
216 |   readonly memory: WebAssembly.Memory;
217 |   readonly __wbindgen_malloc: (a: number, b: number) => number;
218 |   readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
219 |   readonly __wbindgen_export_3: WebAssembly.Table;
220 |   readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h2e88a253da201d98: (a: number, b: number, c: number) => void;
221 |   readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h33fdce4698adb901: (a: number, b: number) => void;
222 |   readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5c02e8a12b71e39b: (a: number, b: number, c: number) => void;
223 |   readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h036d37595979be07: (a: number, b: number, c: number) => void;
224 |   readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
225 |   readonly __wbindgen_free: (a: number, b: number, c: number) => void;
226 |   readonly __wbindgen_exn_store: (a: number) => void;
227 |   readonly wasm_bindgen__convert__closures__invoke2_mut__h134b145bfce1dc02: (a: number, b: number, c: number, d: number) => void;
228 |   readonly __wbindgen_thread_destroy: (a?: number, b?: number, c?: number) => void;
229 |   readonly __wbindgen_start: (a: number) => void;
230 | }
231 | 
232 | export type SyncInitInput = BufferSource | WebAssembly.Module;
233 | /**
234 | * Instantiates the given `module`, which can either be bytes or
235 | * a precompiled `WebAssembly.Module`.
236 | *
237 | * @param {{ module: SyncInitInput, memory?: WebAssembly.Memory, thread_stack_size?: number }} module - Passing `SyncInitInput` directly is deprecated.
238 | * @param {WebAssembly.Memory} memory - Deprecated.
239 | *
240 | * @returns {InitOutput}
241 | */
242 | export function initSync(module: { module: SyncInitInput, memory?: WebAssembly.Memory, thread_stack_size?: number } | SyncInitInput, memory?: WebAssembly.Memory): InitOutput;
243 | 
244 | /**
245 | * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
246 | * for everything else, calls `WebAssembly.instantiate` directly.
247 | *
248 | * @param {{ module_or_path: InitInput | Promise<InitInput>, memory?: WebAssembly.Memory, thread_stack_size?: number }} module_or_path - Passing `InitInput` directly is deprecated.
249 | * @param {WebAssembly.Memory} memory - Deprecated.
250 | *
251 | * @returns {Promise<InitOutput>}
252 | */
253 | export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput>, memory?: WebAssembly.Memory, thread_stack_size?: number } | InitInput | Promise<InitInput>, memory?: WebAssembly.Memory): Promise<InitOutput>;
254 | 
```

--------------------------------------------------------------------------------
/verifier/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { ParsedTranscriptData } from './types';
  2 | 
  3 | export const SEMAPHORE_IDENTITY_HEADER = 'x-semaphore-identity';
  4 | type Stack =
  5 |   | {
  6 |       type: 'object';
  7 |       symbol: string;
  8 |       range: [number, number];
  9 |       id: number;
 10 |     }
 11 |   | {
 12 |       type: 'array';
 13 |       symbol: string;
 14 |       range: [number, number];
 15 |       data: string;
 16 |       id: number;
 17 |     }
 18 |   | {
 19 |       type: 'object_key';
 20 |       symbol: string;
 21 |       range: [number, number];
 22 |       data: string;
 23 |       path: string;
 24 |       id: number;
 25 |       objectId: number;
 26 |     }
 27 |   | {
 28 |       type: 'object_value';
 29 |       symbol: string;
 30 |       range: [number, number];
 31 |       data: string;
 32 |       id: number;
 33 |       keyId: number;
 34 |       objectId: number;
 35 |     }
 36 |   | {
 37 |       type: 'object_value_string';
 38 |       symbol: string;
 39 |       range: [number, number];
 40 |       data: string;
 41 |       path: string;
 42 |       id: number;
 43 |       objectId: number;
 44 |       valueId: number;
 45 |     }
 46 |   | {
 47 |       type: 'object_value_number';
 48 |       symbol: string;
 49 |       range: [number, number];
 50 |       data: string;
 51 |       path: string;
 52 |       id: number;
 53 |       objectId: number;
 54 |       valueId: number;
 55 |     };
 56 | 
 57 | type Commitment = {
 58 |   name?: string;
 59 |   path?: string;
 60 |   start: number;
 61 |   end: number;
 62 | };
 63 | 
 64 | export function processJSON(str: string): Commitment[] {
 65 |   const json = JSON.parse(str);
 66 |   expect(typeof json === 'object', 'json string must be an object');
 67 | 
 68 |   const stack: Stack[] = [];
 69 |   const values: Stack[] = [];
 70 |   const keys: string[] = [];
 71 |   let nonce = 0,
 72 |     keyId = 0;
 73 | 
 74 |   for (let i = 0; i < str.length; i++) {
 75 |     const char = str.charAt(i);
 76 |     let last = stack[stack.length - 1];
 77 | 
 78 |     if (last?.type === 'object_key') {
 79 |       if (char === '"') {
 80 |         last.range[1] = i;
 81 |         const key = stack.pop();
 82 |         expect(key!.type === 'object_key');
 83 |         if (key?.type === 'object_key') {
 84 |           keys.push(key.data);
 85 |           key.path = keys.join('.');
 86 |           values.push(key);
 87 |           keyId = last.id;
 88 |         }
 89 |       } else {
 90 |         last.data = last.data + char;
 91 |       }
 92 |       continue;
 93 |     }
 94 | 
 95 |     if (last?.type === 'object_value_string') {
 96 |       if (char === '"') {
 97 |         last.range[1] = i;
 98 |         values.push(stack.pop()!);
 99 |         const objectValue = stack.pop();
100 |         expect(
101 |           objectValue?.type === 'object_value',
102 |           'expect stack to be object_value',
103 |         );
104 |         objectValue!.range[1] = i;
105 |         values.push(objectValue!);
106 |         keys.pop();
107 |       } else {
108 |         last.data = last.data + char;
109 |       }
110 |       continue;
111 |     }
112 | 
113 |     if (last?.type === 'array') {
114 |       if (char === ']') {
115 |         last.range[1] = i;
116 |         values.push(stack.pop()!);
117 |       } else if (char === '[') {
118 |         stack.push({
119 |           symbol: '[',
120 |           type: 'array',
121 |           id: nonce++,
122 |           range: [i, -1],
123 |           data: '',
124 |         });
125 |       } else {
126 |         last.data = last.data + char;
127 |       }
128 |       continue;
129 |     }
130 | 
131 |     if (last?.type === 'object_value_number') {
132 |       if (char === ',' || char === '}') {
133 |         last.range[1] = i - 1;
134 |         values.push(stack.pop()!);
135 |         const objectValue = stack.pop();
136 |         expect(
137 |           objectValue?.type === 'object_value',
138 |           'expect stack to be object_value',
139 |         );
140 |         objectValue!.range[1] = i - 1;
141 |         values.push(objectValue!);
142 |         last = stack[stack.length - 1];
143 |       } else {
144 |         last.data = last.data + char;
145 |         continue;
146 |       }
147 |     }
148 | 
149 |     if (last?.type === 'object_value') {
150 |       if (char === '}') {
151 |         last.range[1] = i - 1;
152 |         values.push(stack.pop()!);
153 |         const object = stack.pop();
154 |         expect(object?.type === 'object_value', 'expect stack to be object');
155 |         object!.range[1] = i;
156 |         values.push(object!);
157 |         keys.pop();
158 |       } else if (char === ',') {
159 |         last.range[1] = i - 1;
160 |         values.push(stack.pop()!);
161 |         keys.pop();
162 |       } else if (char === '{') {
163 |         stack.push({
164 |           symbol: '{',
165 |           type: 'object',
166 |           id: nonce++,
167 |           range: [i, -1],
168 |         });
169 |       } else if (char === '[') {
170 |         stack.push({
171 |           symbol: '[',
172 |           type: 'array',
173 |           id: nonce++,
174 |           range: [i, -1],
175 |           data: '',
176 |         });
177 |       } else if (char === '"') {
178 |         stack.push({
179 |           symbol: '"',
180 |           type: 'object_value_string',
181 |           objectId: last.objectId,
182 |           valueId: last.id,
183 |           id: nonce++,
184 |           data: '',
185 |           range: [i, -1],
186 |           path: '',
187 |         });
188 |       } else if (/^\d$/.test(char)) {
189 |         stack.push({
190 |           symbol: '"',
191 |           type: 'object_value_number',
192 |           objectId: last.objectId,
193 |           valueId: last.id,
194 |           id: nonce++,
195 |           data: '',
196 |           range: [i, -1],
197 |           path: '',
198 |         });
199 |       }
200 |       continue;
201 |     }
202 | 
203 |     if (last?.type === 'object') {
204 |       switch (char) {
205 |         case '}':
206 |           last.range[1] = i;
207 |           values.push(stack.pop()!);
208 |           continue;
209 |         case '"':
210 |           stack.push({
211 |             symbol: '"',
212 |             type: 'object_key',
213 |             objectId: last.id,
214 |             id: nonce++,
215 |             data: '',
216 |             range: [i, -1],
217 |             path: '',
218 |           });
219 |           continue;
220 |         case ':':
221 |           stack.push({
222 |             symbol: ':',
223 |             type: 'object_value',
224 |             objectId: last.id,
225 |             keyId: keyId,
226 |             id: nonce++,
227 |             range: [i, -1],
228 |             data: '',
229 |           });
230 |           continue;
231 |         default:
232 |           continue;
233 |       }
234 |     }
235 | 
236 |     switch (char) {
237 |       case '{':
238 |         stack.push({
239 |           symbol: '{',
240 |           type: 'object',
241 |           id: nonce++,
242 |           range: [i, -1],
243 |         });
244 |         break;
245 |       case '[':
246 |         stack.push({
247 |           symbol: '[',
248 |           type: 'array',
249 |           id: nonce++,
250 |           range: [i, -1],
251 |           data: '',
252 |         });
253 |         break;
254 |     }
255 |   }
256 | 
257 |   expect(!stack.length, 'invalid stack length');
258 | 
259 |   const commitments: {
260 |     [key: string]: Commitment;
261 |   } = {};
262 | 
263 |   for (const value of values) {
264 |     if (value.type === 'object_key') {
265 |       commitments[value.id] = {
266 |         ...(commitments[value.id] || {}),
267 |         path: value.path,
268 |         start: value.range[0],
269 |       };
270 |     } else if (value.type === 'object_value') {
271 |       commitments[value.keyId] = {
272 |         ...(commitments[value.keyId] || {}),
273 |         end: value.range[1] + 1,
274 |       };
275 |     } else if (value.type === 'object') {
276 |       commitments[value.id] = {
277 |         start: value.range[0],
278 |         end: value.range[1] + 1,
279 |       };
280 |     } else if (value.type === 'array') {
281 |       commitments[value.id] = {
282 |         start: value.range[0],
283 |         end: value.range[1] + 1,
284 |       };
285 |     }
286 |   }
287 | 
288 |   return Object.values(commitments).map(({ path, start, end }) => ({
289 |     path,
290 |     start,
291 |     end,
292 |   }));
293 | }
294 | 
295 | export function processTranscript(transcript: string): ParsedTranscriptData {
296 |   // const commitments: Commitment[] = [];
297 |   const returnVal: ParsedTranscriptData = {
298 |     all: {
299 |       start: 0,
300 |       end: transcript.length,
301 |     },
302 |     info: {
303 |       start: 0,
304 |       end: transcript.indexOf('\n') + 1,
305 |     },
306 |     headers: {},
307 |     lineBreaks: [],
308 |   };
309 | 
310 |   let text = '',
311 |     ptr = -1,
312 |     lineIndex = 0,
313 |     isBody = false;
314 | 
315 |   for (let i = 0; i < transcript.length; i++) {
316 |     const char = transcript.charAt(i);
317 | 
318 |     if (char === '\r') {
319 |       _processEOL(text, i, lineIndex++);
320 |       returnVal.lineBreaks.push({
321 |         start: i,
322 |         end: i + 1,
323 |       });
324 |       continue;
325 |     }
326 | 
327 |     if (char === '\n') {
328 |       text = '';
329 |       ptr = -1;
330 |       returnVal.lineBreaks.push({
331 |         start: i,
332 |         end: i + 1,
333 |       });
334 |       continue;
335 |     }
336 | 
337 |     if (ptr === -1) {
338 |       ptr = i;
339 |     }
340 | 
341 |     text = text + char;
342 |   }
343 | 
344 |   _processEOL(text, transcript.length - 1, lineIndex++);
345 | 
346 |   return returnVal;
347 | 
348 |   function _processEOL(txt: string, index: number, lineIndex: number) {
349 |     try {
350 |       if (!txt) return;
351 |       if (!isNaN(Number(txt))) {
352 |         isBody = true;
353 |         return;
354 |       }
355 | 
356 |       const json = JSON.parse(txt);
357 | 
358 |       returnVal.body = {
359 |         start: ptr,
360 |         end: index,
361 |       };
362 | 
363 |       if (typeof json === 'object') {
364 |         const jsonCommits = processJSON(txt);
365 |         jsonCommits.forEach((commit) => {
366 |           if (commit.path) {
367 |             returnVal.json = returnVal.json || {};
368 |             returnVal.json[commit.path] = {
369 |               start: commit.start + ptr,
370 |               end: commit.end + ptr,
371 |             };
372 |           }
373 |         });
374 |       }
375 |     } catch (e) {
376 |       const [name, value] = txt.split(': ');
377 |       if (lineIndex === 0) {
378 |         returnVal.info = {
379 |           start: ptr,
380 |           end: index,
381 |         };
382 |       } else if (!isBody && value) {
383 |         returnVal.headers = returnVal.headers || {};
384 |         returnVal.headers[name.toLowerCase()] = {
385 |           start: ptr,
386 |           end: index,
387 |         };
388 |       } else if (isBody) {
389 |         returnVal.body = {
390 |           // value: txt,
391 |           start: ptr,
392 |           end: index,
393 |         };
394 |       }
395 |     }
396 |   }
397 | }
398 | 
399 | export function expect(cond: any, msg = 'invalid expression') {
400 |   if (!cond) throw new Error(msg);
401 | }
402 | 
403 | export function stringToBuffer(str: string): number[] {
404 |   return Buffer.from(str).toJSON().data;
405 | }
406 | 
407 | export function arrayToHex(uintArr: Uint8Array): string {
408 |   return Buffer.from(uintArr).toString('hex');
409 | }
410 | 
411 | export function headerToMap(headers: {
412 |   [name: string]: string;
413 | }): Map<string, number[]> {
414 |   const headerMap: Map<string, number[]> = new Map();
415 |   Object.entries(headers).forEach(([key, value]) => {
416 |     headerMap.set(key, stringToBuffer(value));
417 |   });
418 |   return headerMap;
419 | }
420 | 
```

--------------------------------------------------------------------------------
/verifier/wasm/remote-attestation-verifier/remote_attestation_verifier.js:
--------------------------------------------------------------------------------

```javascript
  1 | let wasm;
  2 | 
  3 | function debugString(val) {
  4 |     // primitive types
  5 |     const type = typeof val;
  6 |     if (type == 'number' || type == 'boolean' || val == null) {
  7 |         return  `${val}`;
  8 |     }
  9 |     if (type == 'string') {
 10 |         return `"${val}"`;
 11 |     }
 12 |     if (type == 'symbol') {
 13 |         const description = val.description;
 14 |         if (description == null) {
 15 |             return 'Symbol';
 16 |         } else {
 17 |             return `Symbol(${description})`;
 18 |         }
 19 |     }
 20 |     if (type == 'function') {
 21 |         const name = val.name;
 22 |         if (typeof name == 'string' && name.length > 0) {
 23 |             return `Function(${name})`;
 24 |         } else {
 25 |             return 'Function';
 26 |         }
 27 |     }
 28 |     // objects
 29 |     if (Array.isArray(val)) {
 30 |         const length = val.length;
 31 |         let debug = '[';
 32 |         if (length > 0) {
 33 |             debug += debugString(val[0]);
 34 |         }
 35 |         for(let i = 1; i < length; i++) {
 36 |             debug += ', ' + debugString(val[i]);
 37 |         }
 38 |         debug += ']';
 39 |         return debug;
 40 |     }
 41 |     // Test for built-in
 42 |     const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
 43 |     let className;
 44 |     if (builtInMatches && builtInMatches.length > 1) {
 45 |         className = builtInMatches[1];
 46 |     } else {
 47 |         // Failed to match the standard '[object ClassName]'
 48 |         return toString.call(val);
 49 |     }
 50 |     if (className == 'Object') {
 51 |         // we're a user defined class or Object
 52 |         // JSON.stringify avoids problems with cycles, and is generally much
 53 |         // easier than looping through ownProperties of `val`.
 54 |         try {
 55 |             return 'Object(' + JSON.stringify(val) + ')';
 56 |         } catch (_) {
 57 |             return 'Object';
 58 |         }
 59 |     }
 60 |     // errors
 61 |     if (val instanceof Error) {
 62 |         return `${val.name}: ${val.message}\n${val.stack}`;
 63 |     }
 64 |     // TODO we could test for more things here, like `Set`s and `Map`s.
 65 |     return className;
 66 | }
 67 | 
 68 | let WASM_VECTOR_LEN = 0;
 69 | 
 70 | let cachedUint8ArrayMemory0 = null;
 71 | 
 72 | function getUint8ArrayMemory0() {
 73 |     if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
 74 |         cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
 75 |     }
 76 |     return cachedUint8ArrayMemory0;
 77 | }
 78 | 
 79 | const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
 80 | 
 81 | const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
 82 |     ? function (arg, view) {
 83 |     return cachedTextEncoder.encodeInto(arg, view);
 84 | }
 85 |     : function (arg, view) {
 86 |     const buf = cachedTextEncoder.encode(arg);
 87 |     view.set(buf);
 88 |     return {
 89 |         read: arg.length,
 90 |         written: buf.length
 91 |     };
 92 | });
 93 | 
 94 | function passStringToWasm0(arg, malloc, realloc) {
 95 | 
 96 |     if (realloc === undefined) {
 97 |         const buf = cachedTextEncoder.encode(arg);
 98 |         const ptr = malloc(buf.length, 1) >>> 0;
 99 |         getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
100 |         WASM_VECTOR_LEN = buf.length;
101 |         return ptr;
102 |     }
103 | 
104 |     let len = arg.length;
105 |     let ptr = malloc(len, 1) >>> 0;
106 | 
107 |     const mem = getUint8ArrayMemory0();
108 | 
109 |     let offset = 0;
110 | 
111 |     for (; offset < len; offset++) {
112 |         const code = arg.charCodeAt(offset);
113 |         if (code > 0x7F) break;
114 |         mem[ptr + offset] = code;
115 |     }
116 | 
117 |     if (offset !== len) {
118 |         if (offset !== 0) {
119 |             arg = arg.slice(offset);
120 |         }
121 |         ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
122 |         const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
123 |         const ret = encodeString(arg, view);
124 | 
125 |         offset += ret.written;
126 |         ptr = realloc(ptr, len, offset, 1) >>> 0;
127 |     }
128 | 
129 |     WASM_VECTOR_LEN = offset;
130 |     return ptr;
131 | }
132 | 
133 | let cachedDataViewMemory0 = null;
134 | 
135 | function getDataViewMemory0() {
136 |     if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
137 |         cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
138 |     }
139 |     return cachedDataViewMemory0;
140 | }
141 | 
142 | const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
143 | 
144 | if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
145 | 
146 | function getStringFromWasm0(ptr, len) {
147 |     ptr = ptr >>> 0;
148 |     return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
149 | }
150 | 
151 | function passArray8ToWasm0(arg, malloc) {
152 |     const ptr = malloc(arg.length * 1, 1) >>> 0;
153 |     getUint8ArrayMemory0().set(arg, ptr / 1);
154 |     WASM_VECTOR_LEN = arg.length;
155 |     return ptr;
156 | }
157 | /**
158 |  * @param {Uint8Array} attestation_document
159 |  * @param {Uint8Array} nonce
160 |  * @param {Array<any>} pcrs
161 |  * @returns {boolean}
162 |  */
163 | export function verify_js(attestation_document, nonce, pcrs) {
164 |     const ptr0 = passArray8ToWasm0(attestation_document, wasm.__wbindgen_malloc);
165 |     const len0 = WASM_VECTOR_LEN;
166 |     const ptr1 = passArray8ToWasm0(nonce, wasm.__wbindgen_malloc);
167 |     const len1 = WASM_VECTOR_LEN;
168 |     const ret = wasm.verify_js(ptr0, len0, ptr1, len1, pcrs);
169 |     return ret !== 0;
170 | }
171 | 
172 | async function __wbg_load(module, imports) {
173 |     if (typeof Response === 'function' && module instanceof Response) {
174 |         if (typeof WebAssembly.instantiateStreaming === 'function') {
175 |             try {
176 |                 return await WebAssembly.instantiateStreaming(module, imports);
177 | 
178 |             } catch (e) {
179 |                 if (module.headers.get('Content-Type') != 'application/wasm') {
180 |                     console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
181 | 
182 |                 } else {
183 |                     throw e;
184 |                 }
185 |             }
186 |         }
187 | 
188 |         const bytes = await module.arrayBuffer();
189 |         return await WebAssembly.instantiate(bytes, imports);
190 | 
191 |     } else {
192 |         const instance = await WebAssembly.instantiate(module, imports);
193 | 
194 |         if (instance instanceof WebAssembly.Instance) {
195 |             return { instance, module };
196 | 
197 |         } else {
198 |             return instance;
199 |         }
200 |     }
201 | }
202 | 
203 | function __wbg_get_imports() {
204 |     const imports = {};
205 |     imports.wbg = {};
206 |     imports.wbg.__wbg_buffer_aa30bbb65cb44323 = function(arg0) {
207 |         const ret = arg0.buffer;
208 |         return ret;
209 |     };
210 |     imports.wbg.__wbg_get_01203e6a4116a116 = function(arg0, arg1) {
211 |         const ret = arg0[arg1 >>> 0];
212 |         return ret;
213 |     };
214 |     imports.wbg.__wbg_length_0a11127664108286 = function(arg0) {
215 |         const ret = arg0.length;
216 |         return ret;
217 |     };
218 |     imports.wbg.__wbg_length_9aaa2867670f533a = function(arg0) {
219 |         const ret = arg0.length;
220 |         return ret;
221 |     };
222 |     imports.wbg.__wbg_new_db41cf29086ce106 = function(arg0) {
223 |         const ret = new Uint8Array(arg0);
224 |         return ret;
225 |     };
226 |     imports.wbg.__wbg_set_e97d203fd145cdae = function(arg0, arg1, arg2) {
227 |         arg0.set(arg1, arg2 >>> 0);
228 |     };
229 |     imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
230 |         const ret = debugString(arg1);
231 |         const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
232 |         const len1 = WASM_VECTOR_LEN;
233 |         getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
234 |         getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
235 |     };
236 |     imports.wbg.__wbindgen_init_externref_table = function() {
237 |         const table = wasm.__wbindgen_export_2;
238 |         const offset = table.grow(4);
239 |         table.set(0, undefined);
240 |         table.set(offset + 0, undefined);
241 |         table.set(offset + 1, null);
242 |         table.set(offset + 2, true);
243 |         table.set(offset + 3, false);
244 |         ;
245 |     };
246 |     imports.wbg.__wbindgen_memory = function() {
247 |         const ret = wasm.memory;
248 |         return ret;
249 |     };
250 |     imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
251 |         const ret = getStringFromWasm0(arg0, arg1);
252 |         return ret;
253 |     };
254 |     imports.wbg.__wbindgen_throw = function(arg0, arg1) {
255 |         throw new Error(getStringFromWasm0(arg0, arg1));
256 |     };
257 | 
258 |     return imports;
259 | }
260 | 
261 | function __wbg_init_memory(imports, memory) {
262 | 
263 | }
264 | 
265 | function __wbg_finalize_init(instance, module) {
266 |     wasm = instance.exports;
267 |     __wbg_init.__wbindgen_wasm_module = module;
268 |     cachedDataViewMemory0 = null;
269 |     cachedUint8ArrayMemory0 = null;
270 | 
271 | 
272 |     wasm.__wbindgen_start();
273 |     return wasm;
274 | }
275 | 
276 | function initSync(module) {
277 |     if (wasm !== undefined) return wasm;
278 | 
279 | 
280 |     if (typeof module !== 'undefined') {
281 |         if (Object.getPrototypeOf(module) === Object.prototype) {
282 |             ({module} = module)
283 |         } else {
284 |             console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
285 |         }
286 |     }
287 | 
288 |     const imports = __wbg_get_imports();
289 | 
290 |     __wbg_init_memory(imports);
291 | 
292 |     if (!(module instanceof WebAssembly.Module)) {
293 |         module = new WebAssembly.Module(module);
294 |     }
295 | 
296 |     const instance = new WebAssembly.Instance(module, imports);
297 | 
298 |     return __wbg_finalize_init(instance, module);
299 | }
300 | 
301 | async function __wbg_init(module_or_path) {
302 |     if (wasm !== undefined) return wasm;
303 | 
304 | 
305 |     if (typeof module_or_path !== 'undefined') {
306 |         if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
307 |             ({module_or_path} = module_or_path)
308 |         } else {
309 |             console.warn('using deprecated parameters for the initialization function; pass a single object instead')
310 |         }
311 |     }
312 | 
313 |     if (typeof module_or_path === 'undefined') {
314 |         module_or_path = new URL('remote_attestation_verifier_bg.wasm', import.meta.url);
315 |     }
316 |     const imports = __wbg_get_imports();
317 | 
318 |     if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
319 |         module_or_path = fetch(module_or_path);
320 |     }
321 | 
322 |     __wbg_init_memory(imports);
323 | 
324 |     const { instance, module } = await __wbg_load(await module_or_path, imports);
325 | 
326 |     return __wbg_finalize_init(instance, module);
327 | }
328 | 
329 | export { initSync };
330 | export default __wbg_init;
331 | 
```

--------------------------------------------------------------------------------
/verifier/mcp/react-ts-webpack/src/components/verify-mcp.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React, { ReactElement, useEffect, useState, useRef } from 'react';
  2 | import { CheckCircle, RefreshCw, XCircle } from 'lucide-react';
  3 | import * as Comlink from 'comlink';
  4 | const { init, verify_code_attestation }: any = Comlink.wrap(
  5 |   new Worker(new URL('../utils/worker.ts', import.meta.url)),
  6 | );
  7 | 
  8 | // Utility function to convert hex to base64
  9 | const hexToBase64 = (hexString: string): string => {
 10 |   // Remove any spaces or 0x prefix
 11 |   const cleanedHexString = hexString.replace(/^0x|\s+/g, '');
 12 |   // Convert hex to bytes
 13 |   const bytes = new Uint8Array(cleanedHexString.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []);
 14 |   // Convert bytes to base64
 15 |   return btoa(String.fromCharCode.apply(null, Array.from(bytes)));
 16 | };
 17 | 
 18 | export function VerifyMCP(): ReactElement {
 19 |   const [processingVerification, setProcessingVerification] = useState(false);
 20 |   const [resultVerify, setResultVerify] = useState<boolean | null>(null);
 21 |   const [expectedPcrHex, setExpectedPcrHex] = useState('5591c9354a1d280817ee1230a108c4c343d53fe66e2d8acc84340ddd4fe918d1144606c0cd9ea7f3a090ac3497c1854f');
 22 |   const [codeAttestation, setCodeAttestation] = useState<null | string>(
 23 |     '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'
 24 |   );
 25 |   const [error, setError] = useState<null | string>(null);
 26 |   const textareaRef = useRef<HTMLTextAreaElement>(null);
 27 | 
 28 |   // Function to auto-resize textarea
 29 |   const autoResizeTextarea = () => {
 30 |     const textarea = textareaRef.current;
 31 |     if (textarea) {
 32 |       textarea.style.height = 'auto';
 33 |       textarea.style.height = `${textarea.scrollHeight}px`;
 34 |     }
 35 |   };
 36 | 
 37 |   // Call resize on content change
 38 |   useEffect(() => {
 39 |     autoResizeTextarea();
 40 |   }, [codeAttestation]);
 41 | 
 42 |   const verify_attestation_document = async () => {
 43 |     if (!codeAttestation) {
 44 |       setError('Please enter a valid code attestation');
 45 |       return;
 46 |     }
 47 |     const codeAttestation_ = codeAttestation.replace(/\\n/g, '').trim();
 48 |     const nonce = '0000000000000000000000000000000000000000';
 49 |     
 50 |     // Convert hex PCR to base64 for verification
 51 |     let expectedPcrBase64;
 52 |     try {
 53 |       expectedPcrBase64 = hexToBase64(expectedPcrHex);
 54 |     } catch (e) {
 55 |       setError('Invalid hex format for PCR');
 56 |       return;
 57 |     }
 58 | 
 59 |     setProcessingVerification(true);
 60 | 
 61 |     try {
 62 |       const resultVerify = await verify_code_attestation(
 63 |         codeAttestation_,
 64 |         nonce,
 65 |         expectedPcrBase64,
 66 |         Math.floor(Date.now() / 1000),
 67 |       );
 68 |       setResultVerify(resultVerify);
 69 |     } catch (e) {
 70 |       console.log('error', e);
 71 |       setResultVerify(false);
 72 |       setError((e as Error).message);
 73 |     } finally {
 74 |       setProcessingVerification(false);
 75 |     }
 76 |   };
 77 |   useEffect(() => {
 78 |     const initialize = async () => {
 79 |       await init({ loggingLevel: 'Debug' });
 80 |     };
 81 | 
 82 |     initialize();
 83 |   }, []);
 84 | 
 85 |   return (
 86 |     <div>
 87 |       <div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
 88 |         <div className="flex justify-between items-center mb-4"></div>
 89 | 
 90 |         <div className="mt-2 h-30 overflow-y-auto border border-gray-200 rounded p-4 mb-4">
 91 |           <h1 className="text-2xl font-bold text-center my-4">
 92 |             Verify MCP Server
 93 |           </h1>
 94 |           <div className="mb-4">
 95 |             <h2 className="text-l font-bold">Expected PCR2 Hash</h2>
 96 |             <pre className="bg-gray-100 p-2 rounded text-xs mt-2 mb-2 overflow-x-auto">
 97 |               <code>$ nitro-cli describe-enclaves | jq -r '.[0].Measurements.PCR2'</code>
 98 |             </pre>
 99 |             <textarea
100 |               id="expectedPcr"
101 |               name="expectedPcr"
102 |               className="mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-green-500 focus:ring-green-500 sm:text-sm font-mono"
103 |               placeholder="Expected PCR value in hex format (e.g., 559249354a1d2808...)"
104 |               value={expectedPcrHex}
105 |               onChange={(e) => setExpectedPcrHex(e.target.value)}
106 |             />
107 |           </div>
108 | 
109 |           <h2 className="text-l font-bold">Code attestation</h2>
110 |           <pre className="bg-gray-100 p-2 rounded text-xs mt-2 mb-2 overflow-x-auto">
111 |             <code>$ curl -k https://127.0.0.1:443/enclave/attestation?nonce=0000000000000000000000000000000000000000</code>
112 |           </pre>
113 |           <textarea
114 |             ref={textareaRef}
115 |             id="attestation"
116 |             name="attestation"
117 |             className="mt-1 block w-full min-h-64 overflow-y-auto rounded-md border border-gray-300 shadow-sm focus:border-green-500 focus:ring-green-500 sm:text-sm font-mono"
118 |             placeholder={
119 |               codeAttestation ||
120 |               'Paste the attestation object from the MCP'
121 |             }
122 |             onChange={(e) => {
123 |               setCodeAttestation(e.target.value);
124 |               // Call the resize function after setting the new value
125 |               setTimeout(autoResizeTextarea, 0);
126 |             }}
127 |           />
128 |         </div>
129 | 
130 |         <div className="p-8">
131 |           <div className="flex justify-between items-center mb-4">
132 |             <button
133 |               onClick={verify_attestation_document}
134 |               disabled={processingVerification}
135 |               className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed flex items-center mx-auto"
136 |             >
137 |               {processingVerification ? (
138 |                 <>
139 |                   <RefreshCw className="animate-spin -ml-1 mr-2 h-5 w-5" />
140 |                   Verifying...
141 |                 </>
142 |               ) : (
143 |                 <>
144 |                   <CheckCircle className="mr-2 h-5 w-5" />
145 |                   Verify Attestation
146 |                 </>
147 |               )}
148 |             </button>
149 |           </div>
150 | 
151 |           {resultVerify !== null && (
152 |             <div
153 |               className={`mb-4 mt-4 p-4 rounded-md ${resultVerify ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`}
154 |             >
155 |               <div className="flex items-center ">
156 |                 {!resultVerify && <XCircle className="h-5 w-5 mr-2" />}
157 | 
158 |                 {resultVerify ? (
159 |                   <div>
160 |                     ✅ Code hash matches open-source implementation <br />✅
161 |                     Attestation verified against Amazon's root-of-trust <br />✅
162 |                     Hardware instance authenticity confirmed
163 |                   </div>
164 |                 ) : (
165 |                   <span className="font-medium">
166 |                     Remote attestation is invalid
167 |                   </span>
168 |                 )}
169 |                 {!resultVerify && <p>{error}</p>}
170 |               </div>
171 |             </div>
172 |           )}
173 |         </div>
174 |       </div>
175 |     </div>
176 |   );
177 | }
178 | 
```
Page 1/3FirstPrevNextLast