@@ -7,20 +7,20 @@ import {
77import { getSteamRequestURL } from '../../lib/notary/utils' ;
88import * as Comlink from 'comlink' ;
99import { environment } from '../../environment' ;
10- import {
11- Prover as TProver ,
12- Presentation as TPresentation ,
13- Commit ,
14- NotaryServer ,
15- mapStringToRange ,
16- subtractRanges ,
17- } from 'tlsn-js' ;
18- const { init, Prover, Presentation} : any = Comlink . wrap ( new Worker ( new URL ( '../worker.ts' , import . meta. url ) ) ) ;
10+ import type { LoggingLevel , Method , Prover as TProver , Reveal } from '@csfloat/tlsn-wasm' ;
11+ import { NotarySessionClient } from './notary_session_client' ;
12+ import { Remote } from 'comlink' ;
13+
14+ const { init, Prover} : any = Comlink . wrap ( new Worker ( new URL ( '../worker.ts' , import . meta. url ) ) ) ;
1915
2016export async function initThreads ( ) {
2117 await init ( {
22- loggingLevel : environment . notary . loggingLevel ,
18+ loggingLevel : environment . notary . loggingLevel as LoggingLevel ,
2319 hardwareConcurrency : navigator . hardwareConcurrency ,
20+ crateFilters : [
21+ { name : 'yamux' , level : 'Info' } ,
22+ { name : 'uid_mux' , level : 'Info' } ,
23+ ] ,
2424 } ) ;
2525}
2626
@@ -49,52 +49,65 @@ export const TLSNProveOffscreenHandler = new ClosableOffscreenHandler<
4949
5050 const maxRecvData = await calculateResponseSize ( serverURL , 'GET' , headers ) ;
5151
52- const notary = NotaryServer . from ( environment . notary . tlsn ) ;
53-
54- const prover = ( await new Prover ( {
55- serverDns : 'api.steampowered.com' ,
56- maxRecvData,
57- maxSentData,
58- } ) ) as TProver ;
59-
60- await prover . setup ( await notary . sessionUrl ( ) ) ;
61-
62- await prover . sendRequest ( environment . notary . ws , {
63- url : serverURL ,
64- method : 'GET' ,
65- headers : {
66- 'Accept-Encoding' : 'gzip' ,
67- } ,
68- } ) ;
69-
70- const transcript = await prover . transcript ( ) ;
71- const { sent, recv} = transcript ;
72-
73- const commit : Commit = {
74- sent : subtractRanges (
75- { start : 0 , end : sent . length } ,
76- mapStringToRange ( [ request . access_token . token ] , Buffer . from ( sent ) . toString ( 'utf-8' ) )
77- ) ,
78- recv : [
79- // No secrets in response body
80- { start : 0 , end : recv . length } ,
81- ] ,
82- } ;
83- const notarizationOutputs = await prover . notarize ( commit ) ;
84-
85- const presentation = ( await new Presentation ( {
86- attestationHex : notarizationOutputs . attestation ,
87- secretsHex : notarizationOutputs . secrets ,
88- notaryUrl : notarizationOutputs . notaryUrl ,
89- websocketProxyUrl : notarizationOutputs . websocketProxyUrl ,
90- reveal : { ...commit , server_identity : false } ,
91- } ) ) as TPresentation ;
92-
93- const presentationJSON = await presentation . json ( ) ;
94-
95- return {
96- presentation : presentationJSON ,
97- } ;
52+ const maybeNotaryToken = request . notary_request . meta ?. notary_token ;
53+
54+ const session = await NotarySessionClient . create ( maxRecvData , maxSentData , maybeNotaryToken ) ;
55+
56+ try {
57+ // Create and setup prover
58+ const prover = ( await new Prover ( {
59+ server_name : 'api.steampowered.com' ,
60+ max_recv_data : maxRecvData ,
61+ max_sent_data : maxSentData ,
62+ network : 'Latency' ,
63+ defer_decryption_from_start : true ,
64+ } ) ) as Remote < TProver > ;
65+
66+ let verifierUrl = `${ environment . notary . tlsn } /verifier?sessionId=${ session . getID ( ) } ` ;
67+ if ( maybeNotaryToken ) {
68+ verifierUrl += `&token=${ maybeNotaryToken } ` ;
69+ }
70+
71+ await prover . setup ( verifierUrl ) ;
72+
73+ // Convert headers to Map<string, number[]> for WASM
74+ const headerMap = new Map < string , number [ ] > ( ) ;
75+ for ( const [ key , value ] of Object . entries ( headers ) ) {
76+ headerMap . set ( key , Buffer . from ( value ) . toJSON ( ) . data ) ;
77+ }
78+
79+ let wsUrl = `${ environment . notary . ws } ` ;
80+ if ( maybeNotaryToken ) {
81+ wsUrl += `?token=${ maybeNotaryToken } ` ;
82+ }
83+
84+ // Send HTTP request via proxy
85+ await prover . send_request ( wsUrl , {
86+ uri : serverURL ,
87+ method : 'GET' as Method ,
88+ headers : headerMap ,
89+ body : undefined ,
90+ } ) ;
91+
92+ const { sent, recv} = await prover . transcript ( ) ;
93+ const sentStr = Buffer . from ( sent ) . toString ( 'utf-8' ) ;
94+
95+ // Compute reveal ranges (hide the access token)
96+ const secretRanges = mapStringToRange ( [ request . access_token . token ] , sentStr ) ;
97+ const sentRanges = subtractRanges ( { start : 0 , end : sent . length } , secretRanges ) ;
98+ const recvRanges = [ { start : 0 , end : recv . length } ] ;
99+
100+ // Set up listener before calling reveal
101+ const completedPromise = session . finalizeResults ( ) ;
102+
103+ // Reveal to verifier
104+ const reveal : Reveal = { sent : sentRanges , recv : recvRanges , server_identity : true } ;
105+ await prover . reveal ( reveal ) ;
106+
107+ return await completedPromise ;
108+ } finally {
109+ session . close ( ) ;
110+ }
98111 } ,
99112 ( ) => {
100113 // Require the offscreen to be re-initialized after every 5 prove requests
@@ -179,3 +192,47 @@ async function calculateResponseSize(
179192
180193 return headersSize + bodySize ;
181194}
195+
196+ /**
197+ * Computes ranges that hide specified strings from the transcript
198+ */
199+ function subtractRanges (
200+ fullRange : { start : number ; end : number } ,
201+ secretRanges : { start : number ; end : number } [ ]
202+ ) : { start : number ; end : number } [ ] {
203+ const sorted = [ ...secretRanges ] . sort ( ( a , b ) => a . start - b . start ) ;
204+ const result : { start : number ; end : number } [ ] = [ ] ;
205+ let currentPos = fullRange . start ;
206+
207+ for ( const secret of sorted ) {
208+ if ( secret . start > currentPos ) {
209+ result . push ( { start : currentPos , end : secret . start } ) ;
210+ }
211+ currentPos = Math . max ( currentPos , secret . end ) ;
212+ }
213+
214+ if ( currentPos < fullRange . end ) {
215+ result . push ( { start : currentPos , end : fullRange . end } ) ;
216+ }
217+
218+ return result ;
219+ }
220+
221+ /**
222+ * Maps strings to their byte ranges in the transcript
223+ */
224+ function mapStringToRange ( secrets : string [ ] , transcript : string ) : { start : number ; end : number } [ ] {
225+ const ranges : { start : number ; end : number } [ ] = [ ] ;
226+ for ( const secret of secrets ) {
227+ if ( ! secret ) {
228+ continue ;
229+ }
230+
231+ let pos = 0 ;
232+ while ( ( pos = transcript . indexOf ( secret , pos ) ) !== - 1 ) {
233+ ranges . push ( { start : pos , end : pos + secret . length } ) ;
234+ pos += secret . length ;
235+ }
236+ }
237+ return ranges ;
238+ }
0 commit comments