Dynamically create an Isolated Web App to use Direct Sockets API.
- Substitute Web Cryptography API (wbn-sign-webcrypto) for
node:crypto
implementation 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-plugins
cd webbundle-plugins/packages/rollup-plugin-webbundle
bun install -p
- In
src/index.ts
comment 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:crypto
directlyimport { webcrypto } from "node:crypto";
- In
/node_modules/wbn-sign/lib/utils/utils.js
useswitch (key.algorithm.name) {
getRawPublicKey
becomes anasync
function 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.js
useconst publicKey = await signingStrategy.getPublicKey();
and[getPublicKeyAttributeName(publicKey)]: await getRawPublicKey(publicKey)
;verifySignature()
also becomes anasync
function 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.js
serialize()
function becomesasync
forreturn base32Encode(new Uint8Array([...await getRawPublicKey(this.key), ...this.typeSuffix]), "RFC4648", { padding: false }).toLowerCase();
; andserializeWithIsolatedWebAppOrigin()
becomes anasync
function forreturn ${this.scheme}${await this.serialize()}/;
;toString()
becomes anasync
function forreturn Web Bundle ID: ${await this.serialize()} Isolated Web App Origin: ${await this.serializeWithIsolatedWebAppOrigin()};
- In
src/index.ts
export {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-sockets
folder. - Note the generated extension ID.
- Open
nm_tcpsocket.json
in 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.json
file to Chrome or Chromium configuration folder, e.g., on Chromium on Linux~/.config/chromium/NativeMessagingHosts
. - Make sure the TCP echo server
*.js
file 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()
.