Dynamically create an Isolated Web App to use Direct Sockets API.
- Substitute Web Cryptography API (wbn-sign-webcrypto) for
node:cryptoimplementation of Ed25519 algorithm - Install and run same JavaScript source code in different JavaScript runtimes, e.g.,
node,deno,bun - TODO: Create Signed Web Bundle and Isolated Web App in the browser
Creates a node_modules folder containing dependencies
bun install
or
npm install
or
deno add npm:wbn
This only has to be done once. generateWebCryptoKeys.js can be run with node, deno, or bun.
bun run generateWebCryptoKeys.js
Entry point is assets directory; contains manifest.webmanifest, index.html, script.js and any other scripts or resources to be bundled.
Write signed.swbn to current directory, and write the generated Signed Web Bundle isolated-app: ID to direct-socket-controller.js in direct-sockets extension folder.
Node.js
node index.js
Bun
bun run index.js
Deno (Can be run without node_modules folder in current directory; fetches dependencies from https://esm.sh)
deno -A --import-map import-map index.js
Build/rebuild wbn-bundle.js from webbundle-plugins/packages/rollup-plugin-webbundle/src/index.ts with bun
git clone https://github.com/GoogleChromeLabs/webbundle-pluginscd webbundle-plugins/packages/rollup-plugin-webbundlebun install -p- In
src/index.tscomment line 18,: EnforcedPlugin, line 32const opts = await getValidatedOptionsWithDefaults(rawOpts);and lines 65-121, because I will not be using Rollup - Bundle with Bun
bun build --target=node --format=esm --sourcemap=none --outfile=webpackage-bundle.js ./webbundle-plugins/packages/rollup-plugin-webbundle/src/index.ts - Create reference to Web Cryptography API that will be used in the code in the bundled script instead of
node:cryptodirectlyimport { webcrypto } from "node:crypto"; - In
/node_modules/wbn-sign/lib/utils/utils.jsuseswitch (key.algorithm.name) { getRawPublicKeybecomes anasyncfunction for substitutingconst exportedKey = await webcrypto.subtle.exportKey("spki", publicKey);forpublicKey.export({ type: "spki", format: "der" });- In
/node_modules/wbn-sign/lib/signers/integrity-block-signer.jsuseconst publicKey = await signingStrategy.getPublicKey();and[getPublicKeyAttributeName(publicKey)]: await getRawPublicKey(publicKey);verifySignature()also becomes anasyncfunction whereconst algorithm = { name: "Ed25519" }; const isVerified = await webcrypto.subtle.verify(algorithm, publicKey, signature, data);is substituted forconst isVerified = crypto2.verify(undefined, data, publicKey, signature); - In
/node_modules/wbn-sign/lib/web-bundle-id.jsserialize()function becomesasyncforreturn base32Encode(new Uint8Array([...await getRawPublicKey(this.key), ...this.typeSuffix]), "RFC4648", { padding: false }).toLowerCase();; andserializeWithIsolatedWebAppOrigin()becomes anasyncfunction forreturn ${this.scheme}${await this.serialize()}/;;toString()becomes anasyncfunction forreturn Web Bundle ID: ${await this.serialize()} Isolated Web App Origin: ${await this.serializeWithIsolatedWebAppOrigin()}; - In
src/index.tsexport {WebBundleId, bundleIsolatedWebApp}; - In
index.js, the entry point for how I am creating the SWBN and IWA I get the public and private keys created with Web Cryptography API, and use Web Cryptography API to sign and verify
- Navigate to
chrome://extensions. - Toggle
Developer mode. - Click
Load unpacked. - Select
direct-socketsfolder. - Note the generated extension ID.
- Open
nm_tcpsocket.jsonin a text editor, set"path"to absolute path of Denodeno_echo_tcp.js, txiki.jstxikijs_echo_tcp.js, Bunbun_echo_tcp.js, and Node.js TCP serversnode_echo_tcp.js, and set"allowed_origins"array value tochrome-extension://<ID>/using ID from 5 . - Copy the
nm_tcpsocket.jsonfile to Chrome or Chromium configuration folder, e.g., on Chromium on Linux~/.config/chromium/NativeMessagingHosts. - Make sure the TCP echo server
*.jsfile is executable.
To launch the IWA window from an arbitrary Web page run the code in /direct-sockets/direct-socket-controller.js in DevTools console or Snippets.
We could recently open the IWA window from arbitrary Web sites in DevTools console or Snippets with
var iwa = open("isolated-app://<IWA_ID>");
iwa: Mark isolated-app: as being handled by Chrome evidently had the side effect of blocking that capability, see window.open("isolated-app://") is blocked. isolated-web-app-utilities provides approaches to open the IWA window from arbitrary Web sites, chrome:, chrome-extension: URL's.
Activate the notification which will prompt to save the generated WebRTC RTCPeerConnection SDP to the file direct-socket-controller.sdp in Downloads folder, click Save. Activate the second notification and select the direct-socket-controller.sdp file from Downloads folder. Click to save changes if prompted.
The calling Web page will create a WebRTC Data Channel, and pass the SDP to the Isolated Web App in a new window using open(), then exchange SDP with a WebRTC Data Channel in the Isolated Web App to facilitate bi-directional communication between the arbitrary Web page and the IWA where a TCPSocket communicates with a local (or remote) TCP server.
Watch for the open event of the WebRTC Data Channel connection between the IWA and the current Web page, then run something like the following which should print the values echoed back in uppercase
channel.send(encoder.encode("live")); // "LIVE" in channel.onmessage handler
The direct-sockets browser extension starts one of the above local TCP servers specified in nm_tcpsocket.json.
To close the TCP connection and the Isolated Web App window call channel.close().