@@ -9,34 +9,97 @@ const __frozenTimeMs =
99 : Date . now ( ) ;
1010const __frozenDateNow = ( ) => __frozenTimeMs ;
1111
12+ // Freeze Date.now — non-configurable + non-writable prevents sandbox override
1213try {
1314 Object . defineProperty ( Date , "now" , {
1415 value : __frozenDateNow ,
15- configurable : true ,
16- writable : true ,
16+ configurable : false ,
17+ writable : false ,
1718 } ) ;
1819} catch {
1920 Date . now = __frozenDateNow ;
2021}
2122
23+ // Patch Date constructor so new Date().getTime() returns degraded time
24+ const __OrigDate = Date ;
25+ const __FrozenDate = function Date (
26+ this : InstanceType < DateConstructor > ,
27+ ...args : unknown [ ]
28+ ) {
29+ if ( new . target ) {
30+ // Called with new — no-arg returns frozen time, with args passes through
31+ if ( args . length === 0 ) {
32+ return new __OrigDate ( __frozenTimeMs ) ;
33+ }
34+ // @ts -expect-error — spread forwarding to variadic Date constructor
35+ return new __OrigDate ( ...args ) ;
36+ }
37+ // Called without new — Date() returns string like original
38+ return __OrigDate ( ) ;
39+ } as unknown as DateConstructor ;
40+ Object . defineProperty ( __FrozenDate , "prototype" , {
41+ value : __OrigDate . prototype ,
42+ writable : false ,
43+ configurable : false ,
44+ } ) ;
45+ __FrozenDate . now = __frozenDateNow ;
46+ __FrozenDate . parse = __OrigDate . parse ;
47+ __FrozenDate . UTC = __OrigDate . UTC ;
48+ // Lock Date.now on the replacement constructor too
49+ Object . defineProperty ( __FrozenDate , "now" , {
50+ value : __frozenDateNow ,
51+ configurable : false ,
52+ writable : false ,
53+ } ) ;
54+ try {
55+ Object . defineProperty ( globalThis , "Date" , {
56+ value : __FrozenDate ,
57+ configurable : false ,
58+ writable : false ,
59+ } ) ;
60+ } catch {
61+ ( globalThis as Record < string , unknown > ) . Date = __FrozenDate ;
62+ }
63+
64+ /* Replace globalThis.performance with a frozen proxy — native V8 performance
65+ may have non-configurable properties that prevent in-place freezing. */
2266const __frozenPerformanceNow = ( ) => 0 ;
23- const __performance = globalThis . performance ;
24- if ( typeof __performance !== "undefined" && __performance !== null ) {
25- try {
26- Object . defineProperty ( __performance , "now" , {
27- value : __frozenPerformanceNow ,
28- configurable : true ,
29- writable : true ,
30- } ) ;
31- } catch {
32- try {
33- Object . assign ( __performance , { now : __frozenPerformanceNow } ) ;
34- } catch { }
67+ const __origPerf = globalThis . performance ;
68+ const __frozenPerf = Object . create ( null ) as Record < string , unknown > ;
69+ // Copy existing methods/properties, override now()
70+ if ( typeof __origPerf !== "undefined" && __origPerf !== null ) {
71+ const src = __origPerf as unknown as Record < string , unknown > ;
72+ for ( const key of Object . getOwnPropertyNames (
73+ Object . getPrototypeOf ( __origPerf ) ?? __origPerf ,
74+ ) ) {
75+ if ( key !== "now" ) {
76+ try {
77+ const val = src [ key ] ;
78+ if ( typeof val === "function" ) {
79+ __frozenPerf [ key ] = val . bind ( __origPerf ) ;
80+ } else {
81+ __frozenPerf [ key ] = val ;
82+ }
83+ } catch {
84+ /* skip inaccessible properties */
85+ }
86+ }
3587 }
36- } else {
37- setGlobalValue ( "performance" , {
38- now : __frozenPerformanceNow ,
88+ }
89+ Object . defineProperty ( __frozenPerf , "now" , {
90+ value : __frozenPerformanceNow ,
91+ configurable : false ,
92+ writable : false ,
93+ } ) ;
94+ Object . freeze ( __frozenPerf ) ;
95+ try {
96+ Object . defineProperty ( globalThis , "performance" , {
97+ value : __frozenPerf ,
98+ configurable : false ,
99+ writable : false ,
39100 } ) ;
101+ } catch {
102+ ( globalThis as Record < string , unknown > ) . performance = __frozenPerf ;
40103}
41104
42105/* Harden SharedArrayBuffer removal — neuter prototype so saved refs are useless,
0 commit comments