diff --git a/cert/generate b/cert/generate index 720fcfd..d89953d 100755 --- a/cert/generate +++ b/cert/generate @@ -17,4 +17,4 @@ go run filippo.io/mkcert -ecdsa -install go run filippo.io/mkcert -ecdsa -days 10 -cert-file "$CRT" -key-file "$KEY" localhost 127.0.0.1 ::1 # Compute the sha256 fingerprint of the certificate for WebTransport -openssl x509 -in "$CRT" -outform der | openssl dgst -sha256 > ../player/src/transport/fingerprint.hex +openssl x509 -in "$CRT" -outform der | openssl dgst -sha256 > ../player/fingerprint.hex diff --git a/player/.gitignore b/player/.gitignore index 6d34cdf..10ec168 100644 --- a/player/.gitignore +++ b/player/.gitignore @@ -1,3 +1,4 @@ node_modules .parcel-cache dist +fingerprint.hex diff --git a/player/src/index.ts b/player/src/index.ts index dfa93a9..e691ab5 100644 --- a/player/src/index.ts +++ b/player/src/index.ts @@ -1,5 +1,14 @@ import Player from "./player" +// @ts-ignore embed the certificate fingerprint using bundler +import fingerprintHex from 'bundle-text:../fingerprint.hex'; + +// Convert the hex to binary. +let fingerprint = []; +for (let c = 0; c < fingerprintHex.length-1; c += 2) { + fingerprint.push(parseInt(fingerprintHex.substring(c, c+2), 16)); +} + const params = new URLSearchParams(window.location.search) const url = params.get("url") || "https://localhost:4443/watch" @@ -7,6 +16,10 @@ const canvas = document.querySelector("canvas#video")! const player = new Player({ url: url, + fingerprint: { // TODO remove when Chrome accepts the system CA + "algorithm": "sha-256", + "value": new Uint8Array(fingerprint), + }, canvas: canvas, }) diff --git a/player/src/player/index.ts b/player/src/player/index.ts index 00438b2..b18a625 100644 --- a/player/src/player/index.ts +++ b/player/src/player/index.ts @@ -4,6 +4,7 @@ import Video from "../video" export interface PlayerInit { url: string; + fingerprint?: WebTransportHash; // the certificate fingerprint, temporarily needed for local development canvas: HTMLCanvasElement; } @@ -20,6 +21,8 @@ export default class Player { this.transport = new Transport({ url: props.url, + fingerprint: props.fingerprint, + audio: this.audio, video: this.video, }) @@ -29,10 +32,6 @@ export default class Player { this.transport.close() } - async connect(url: string) { - await this.transport.connect(url) - } - play() { this.audio.play({}) //this.video.play() diff --git a/player/src/transport/.gitignore b/player/src/transport/.gitignore deleted file mode 100644 index 628e634..0000000 --- a/player/src/transport/.gitignore +++ /dev/null @@ -1 +0,0 @@ -fingerprint.hex diff --git a/player/src/transport/index.ts b/player/src/transport/index.ts index 138688d..90bb29b 100644 --- a/player/src/transport/index.ts +++ b/player/src/transport/index.ts @@ -5,11 +5,10 @@ import * as MP4 from "../mp4" import Audio from "../audio" import Video from "../video" -// @ts-ignore bundler embeds data -import fingerprint from 'bundle-text:./fingerprint.hex'; - export interface TransportInit { url: string; + fingerprint?: WebTransportHash; // the certificate fingerprint, temporarily needed for local development + audio: Audio; video: Video; } @@ -28,7 +27,7 @@ export default class Transport { this.audio = props.audio; this.video = props.video; - this.quic = this.connect(props.url) + this.quic = this.connect(props) // Create a unidirectional stream for all of our messages this.api = this.quic.then((q) => { @@ -43,22 +42,16 @@ export default class Transport { (await this.quic).close() } - async connect(url: string): Promise { - // Convert the hex to binary. - let hash = []; - for (let c = 0; c < fingerprint.length-1; c += 2) { - hash.push(parseInt(fingerprint.substring(c, c+2), 16)); + // Helper function to make creating a promise easier + private async connect(props: TransportInit): Promise { + + let options: WebTransportOptions = {}; + if (props.fingerprint) { + options.serverCertificateHashes = [ props.fingerprint ] } - const quic = new WebTransport(url, { - "serverCertificateHashes": [{ - "algorithm": "sha-256", - "value": new Uint8Array(hash), - }] - }) - + const quic = new WebTransport(props.url, options) await quic.ready - return quic }