diff --git a/.gitignore b/.gitignore index 49eea80..9e610e7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ pnpm-lock.yaml build/ dev-build/ test-build/ +./demo/node_modules +./demo/package-lock.json \ No newline at end of file diff --git a/demo/react-ts-webpack/.gitignore b/demo/react-ts-webpack/.gitignore new file mode 100644 index 0000000..d8b83df --- /dev/null +++ b/demo/react-ts-webpack/.gitignore @@ -0,0 +1 @@ +package-lock.json diff --git a/demo/react-ts-webpack/app.tsx b/demo/react-ts-webpack/app.tsx new file mode 100644 index 0000000..dfb7daf --- /dev/null +++ b/demo/react-ts-webpack/app.tsx @@ -0,0 +1,87 @@ +import React, { ReactElement, useCallback, useEffect, useState } from 'react'; +import { createRoot } from 'react-dom/client'; +import { prove, verify } from '../../src'; +import { Proof } from 'tlsn-js/build/types'; +import { Watch } from 'react-loader-spinner' + +const container = document.getElementById('root'); +const root = createRoot(container!); + +root.render(); + +function App(): ReactElement { + const [processing, setProcessing] = useState(false); + const [result, setResult] = useState<{ + time: number; + sent: string; + recv: string; + notaryUrl: string; + } | null>(null); + const [proof, setProof] = useState(null); + + const onClick = useCallback(async () => { + setProcessing(true); + const p = await prove('https://swapi.dev/api/people/1', { + method: 'GET', + maxTranscriptSize: 16384, + notaryUrl: 'http://localhost:7047', + websocketProxyUrl: 'ws://localhost:55688', + }); + setProof(p); + }, [setProof, setProcessing]); + + useEffect(() => { + (async () => { + if (proof) { + const r = await verify(proof); + setResult(r); + setProcessing(false); + } + })(); + }, [proof, setResult]); + + return ( + + + Start demo + + + Proof: + {!processing && !proof + ? not started + : !proof + ? <> + Proving data from swapi... + + Open Developer tools to follow progress + > + : <> + + View Proof + {JSON.stringify(proof, null, 2)} + + > + } + + + + Verification: + {!proof + ? not started + : !result + ? verifying + : {JSON.stringify(result, null, 2)} + } + + + ); +} diff --git a/demo/react-ts-webpack/index.ejs b/demo/react-ts-webpack/index.ejs new file mode 100644 index 0000000..7bd6dac --- /dev/null +++ b/demo/react-ts-webpack/index.ejs @@ -0,0 +1,16 @@ + + + + + + + React/Typescrip Example + + + + + + + + \ No newline at end of file diff --git a/demo/react-ts-webpack/package.json b/demo/react-ts-webpack/package.json new file mode 100644 index 0000000..dbb364b --- /dev/null +++ b/demo/react-ts-webpack/package.json @@ -0,0 +1,30 @@ +{ + "name": "react-ts-webpack", + "version": "1.0.0", + "description": "", + "main": "webpack.js", + "scripts": { + "dev": "webpack-dev-server --config webpack.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-loader-spinner": "^6.1.6", + "tlsn-js": "../../../tlsn-js" + }, + "devDependencies": { + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.10", + "babel-loader": "^9.1.3", + "copy-webpack-plugin": "^11.0.0", + "html-webpack-plugin": "^5.5.0", + "source-map-loader": "^5.0.0", + "ts-loader": "^9.4.2", + "typescript": "^4.9.4", + "webpack": "^5.75.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.11.1" + } +} diff --git a/demo/react-ts-webpack/tsconfig.json b/demo/react-ts-webpack/tsconfig.json new file mode 100644 index 0000000..226acce --- /dev/null +++ b/demo/react-ts-webpack/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "noEmit": false, + "jsx": "react" + }, + "include": ["app.tsx"] +} \ No newline at end of file diff --git a/demo/react-ts-webpack/webpack.js b/demo/react-ts-webpack/webpack.js new file mode 100644 index 0000000..d387c70 --- /dev/null +++ b/demo/react-ts-webpack/webpack.js @@ -0,0 +1,100 @@ +var webpack = require('webpack'), + path = require('path'), + HtmlWebpackPlugin = require('html-webpack-plugin'); + +const ASSET_PATH = process.env.ASSET_PATH || '/'; + +var alias = {}; + +var fileExtensions = [ + 'jpg', + 'jpeg', + 'png', + 'gif', + 'eot', + 'otf', + 'svg', + 'ttf', + 'woff', + 'woff2', +]; + +var options = { + ignoreWarnings: [ + /Circular dependency between chunks with runtime/, + /ResizeObserver loop completed with undelivered notifications/, + ], + mode: 'development', + entry: { + app: path.join(__dirname, 'app.tsx'), + }, + output: { + filename: '[name].bundle.js', + path: path.resolve(__dirname, 'build'), + clean: true, + publicPath: ASSET_PATH, + }, + module: { + rules: [ + { + test: new RegExp('.(' + fileExtensions.join('|') + ')$'), + type: 'asset/resource', + exclude: /node_modules/, + }, + { + test: /\.html$/, + loader: 'html-loader', + exclude: /node_modules/, + }, + { + test: /\.(ts|tsx)$/, + exclude: /node_modules/, + use: [ + { + loader: require.resolve('ts-loader'), + }, + ], + }, + { + test: /\.(js|jsx)$/, + use: [ + { + loader: 'source-map-loader', + }, + { + loader: require.resolve('babel-loader'), + }, + ], + exclude: /node_modules/, + }, + ], + }, + resolve: { + alias: alias, + extensions: fileExtensions + .map((extension) => '.' + extension) + .concat(['.js', '.jsx', '.ts', '.tsx', '.css']), + }, + plugins: [ + new HtmlWebpackPlugin({ + template: path.join(__dirname, 'index.ejs'), + filename: 'index.html', + cache: false, + }), + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + }), + ].filter(Boolean), + // Required by wasm-bindgen-rayon, in order to use SharedArrayBuffer on the Web + // Ref: + // - https://github.com/GoogleChromeLabs/wasm-bindgen-rayon#setting-up + // - https://web.dev/i18n/en/coop-coep/ + devServer: { + headers: { + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Opener-Policy': 'same-origin', + }, + }, +}; + +module.exports = options; diff --git a/package.json b/package.json index 42838c1..7f38364 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "build:wasm": "wasm-pack build --target web wasm/prover", "watch:dev": "webpack --config webpack.web.dev.config.js --watch", "predev": "sh utils/check-wasm.sh", - "dev": "concurrently npm:watch:dev npm:serve:dev", "lint:wasm": "cd wasm/prover; cargo clippy --target wasm32-unknown-unknown", + "dev": "concurrently npm:watch:dev npm:serve:test", "lint:eslint": "eslint . --fix", "lint:tsc": "tsc --noEmit", "lint": "concurrently npm:lint:tsc npm:lint:eslint", diff --git a/quickstart.md b/quickstart.md new file mode 100644 index 0000000..8910084 --- /dev/null +++ b/quickstart.md @@ -0,0 +1,62 @@ +# Quick Start Guide + +There is a simple react/typescript demo app in `./demo/react-ts-webpack`. The directory contains a webpack configuration file that allows you to quickly bootstrap a webpack app using tlsn-js. + +## Run a local notary server and websocket proxy + +### Websocket Proxy + +Since a web browser doesn't have the ability to make TCP connection, we need to use a websocket proxy server. + +To run your own websockify proxy **locally**, run: +```sh +git clone https://github.com/novnc/websockify && cd websockify +./docker/build.sh +docker run -it --rm -p 55688:80 novnc/websockify 80 swapi.dev:443 +``` + +Note the `swapi.dev:443` argument on the last line, this is the server we will use in this quick start. + +### Run a Local Notary Server + +For this demo, we also need to run a local notary server. + +1. Clone the TLSNotary repository: + ```shell + git clone https://github.com/tlsnotary/tlsn.git --branch "v0.1.0-alpha.4" + ``` +2. Edit the notary server config file (`notary-server/config/config.yaml`) to turn off TLS so that the browser extension can connect to the local notary server without requiring extra steps to accept self-signed certificates in the browser. + ```yaml + tls: + enabled: false + ``` +3. Run the notary server: + ```shell + cd notary-server + cargo run --release + ``` + +The notary server will now be running in the background waiting for connections. + +## `tlsn-js` in a React/Typescript app + +### Run the +1. Clone the repository + ```sh + git clone https://github.com/tlsnotary/tlsn-js + ``` +2. Go to the demo folder + ```sh + cd ./tlsn-js/demo/react-ts-webpack + ``` +3. Install dependencies + ```sh + npm i + ``` +4. Start Webpack Dev Server: + ``` + npm run dev + ``` +5. Open `http://localhost:8080` in your browser +6. Click the **start demo** button +7. Open developer tools and monitor the console logs
{JSON.stringify(proof, null, 2)}
{JSON.stringify(result, null, 2)}