@@ -16,13 +16,19 @@ import {
1616 op_set_default_ca_certificates ,
1717} from "ext:core/ops" ;
1818import { core , primordials } from "ext:core/mod.js" ;
19+ import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts" ;
20+ import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts" ;
1921
22+ const { isTypedArray } = core ;
2023const {
2124 ArrayIsArray,
2225 ArrayPrototypeIncludes,
2326 ArrayPrototypeForEach,
2427 ArrayPrototypeMap,
2528 ArrayPrototypePush,
29+ DataViewPrototypeGetBuffer,
30+ DataViewPrototypeGetByteLength,
31+ DataViewPrototypeGetByteOffset,
2632 ObjectDefineProperty,
2733 ObjectKeys,
2834 ObjectFreeze,
@@ -40,9 +46,36 @@ const {
4046 StringPrototypeSplit,
4147 StringPrototypeTrim,
4248 StringPrototypeToLowerCase,
43- TypeError,
49+ TypedArrayPrototypeGetBuffer,
50+ TypedArrayPrototypeGetByteLength,
51+ TypedArrayPrototypeGetByteOffset,
52+ Uint8Array,
4453} = primordials ;
4554
55+ // Lazy-init: tls.ts is loaded into the startup snapshot before TextDecoder
56+ // is registered as a global, so a top-level `new TextDecoder()` would throw.
57+ let utf8Decoder : TextDecoder | null = null ;
58+
59+ // deno-lint-ignore no-explicit-any
60+ function arrayBufferViewToString ( view : any ) : string {
61+ // Use the matching prototype getter so a forged accessor on the view
62+ // can't redirect us to a different ArrayBuffer / out-of-bounds region.
63+ const isTA = isTypedArray ( view ) ;
64+ const buffer = isTA
65+ ? TypedArrayPrototypeGetBuffer ( view )
66+ : DataViewPrototypeGetBuffer ( view ) ;
67+ const byteOffset = isTA
68+ ? TypedArrayPrototypeGetByteOffset ( view )
69+ : DataViewPrototypeGetByteOffset ( view ) ;
70+ const byteLength = isTA
71+ ? TypedArrayPrototypeGetByteLength ( view )
72+ : DataViewPrototypeGetByteLength ( view ) ;
73+ if ( utf8Decoder === null ) {
74+ utf8Decoder = new TextDecoder ( "utf-8" ) ;
75+ }
76+ return utf8Decoder . decode ( new Uint8Array ( buffer , byteOffset , byteLength ) ) ;
77+ }
78+
4679// openssl -> rustls
4780const cipherMap = {
4881 "__proto__" : null ,
@@ -187,28 +220,43 @@ export class CryptoStream {}
187220export class SecurePair { }
188221export const Server = tlsWrap . Server ;
189222
190- export function setDefaultCACertificates ( certs : string [ ] ) {
223+ export function setDefaultCACertificates (
224+ certs : ( string | ArrayBufferView ) [ ] ,
225+ ) {
191226 if ( ! ArrayIsArray ( certs ) ) {
192- throw new TypeError (
193- "The argument 'certs' must be an array of strings" ,
194- ) ;
227+ throw new ERR_INVALID_ARG_TYPE ( "certs" , "Array" , certs ) ;
195228 }
196229
230+ const normalized : string [ ] = [ ] ;
197231 for ( let i = 0 ; i < certs . length ; ++ i ) {
198232 const cert = certs [ i ] ;
199- if ( typeof cert !== "string" ) {
200- throw new TypeError (
201- "Each certificate in 'certs' must be a string" ,
233+ if ( typeof cert === "string" ) {
234+ ArrayPrototypePush ( normalized , cert ) ;
235+ } else if ( isArrayBufferView ( cert ) ) {
236+ ArrayPrototypePush ( normalized , arrayBufferViewToString ( cert ) ) ;
237+ } else {
238+ throw new ERR_INVALID_ARG_TYPE (
239+ `certs[${ i } ]` ,
240+ [ "string" , "ArrayBufferView" ] ,
241+ cert ,
202242 ) ;
203243 }
204244 }
205245
206- op_set_default_ca_certificates ( certs ) ;
246+ op_set_default_ca_certificates ( normalized ) ;
207247
208- lazyRootCertificates = null ;
248+ // The bundled root certificates (`rootCertificates` proxy /
249+ // `lazyRootCertificates`) come from the webpki Mozilla bundle and don't
250+ // change here, so don't invalidate them: doing so would re-enter
251+ // `ensureLazyRootCertificates` and try to mutate a frozen target.
252+ // Only the 'default' cache reflects what we just wrote.
209253 ArrayPrototypeForEach (
210254 ObjectKeys ( cachedCACertificates ) ,
211- ( key ) => delete cachedCACertificates [ key ] ,
255+ ( key ) => {
256+ if ( key !== "bundled" ) {
257+ delete cachedCACertificates [ key ] ;
258+ }
259+ } ,
212260 ) ;
213261}
214262
0 commit comments