@@ -12,11 +12,17 @@ interface Anchor {
12
12
} ;
13
13
}
14
14
15
+ interface BasicAuthConfig {
16
+ username : string ;
17
+ password : string ;
18
+ }
19
+
15
20
interface UpdateOptions {
16
21
localPath ?: string ; // Local file
17
22
remoteUrls ?: string [ ] ; // Remote endpoints to fetch anchor file
18
23
staticAnchors ?: Anchor [ ] ; // Use the following static anchors
19
24
checkIntervalMs ?: number ; // Periodic refresh
25
+ basicAuth ?: BasicAuthConfig ;
20
26
}
21
27
22
28
export class AnchorStore {
@@ -198,12 +204,59 @@ export class AnchorStore {
198
204
return null ;
199
205
}
200
206
207
+ private extractAuthFromUrl ( url : string ) : { username : string ; password : string } | null {
208
+ try {
209
+ const urlObj = new URL ( url ) ;
210
+ if ( urlObj . username && urlObj . password ) {
211
+ return {
212
+ username : decodeURIComponent ( urlObj . username ) ,
213
+ password : decodeURIComponent ( urlObj . password )
214
+ } ;
215
+ }
216
+ } catch ( err ) {
217
+ log ( `Invalid URL format: ${ url } ` ) ;
218
+ }
219
+ return null ;
220
+ }
221
+
222
+ private cleanUrl ( url : string ) : string {
223
+ try {
224
+ const urlObj = new URL ( url ) ;
225
+ urlObj . username = '' ;
226
+ urlObj . password = '' ;
227
+ return urlObj . toString ( ) ;
228
+ } catch ( err ) {
229
+ log ( `Invalid URL format: ${ url } ` ) ;
230
+ return url ;
231
+ }
232
+ }
233
+
234
+ private createAuthHeaders ( url : string ) : HeadersInit {
235
+ const headers : HeadersInit = { } ;
236
+ const authFromUrl = this . extractAuthFromUrl ( url ) ;
237
+ if ( authFromUrl ) {
238
+ const credentials = Buffer . from ( `${ authFromUrl . username } :${ authFromUrl . password } ` ) . toString ( 'base64' ) ;
239
+ headers [ 'Authorization' ] = `Basic ${ credentials } ` ;
240
+ } else if ( this . options . basicAuth ) {
241
+ const { username, password } = this . options . basicAuth ;
242
+ const credentials = Buffer . from ( `${ username } :${ password } ` ) . toString ( 'base64' ) ;
243
+ headers [ 'Authorization' ] = `Basic ${ credentials } ` ;
244
+ }
245
+
246
+ return headers ;
247
+ }
248
+
201
249
private async fetchAnchorsFromRemotes ( remoteUrls : string [ ] ) : Promise < Anchor [ ] > {
202
250
const responses = await Promise . all (
203
251
remoteUrls . map ( async url => {
204
252
log ( `Fetching anchors from: ${ url } ` ) ;
205
253
try {
206
- const res = await fetch ( url ) ;
254
+ const authHeaders = this . createAuthHeaders ( url ) ;
255
+ const cleanUrl = this . cleanUrl ( url ) ;
256
+
257
+ const res = await fetch ( cleanUrl , {
258
+ headers : authHeaders
259
+ } ) ;
207
260
if ( ! res . ok ) {
208
261
throw new Error ( `Status: ${ res . status } ` ) ;
209
262
}
@@ -238,9 +291,9 @@ export class AnchorStore {
238
291
for ( const group of groups . values ( ) ) {
239
292
if (
240
293
! chosen ||
241
- group . count > chosen . count ||
242
- ( group . count === chosen . count &&
243
- group . anchors [ 0 ] . block . height > chosen . anchors [ 0 ] . block . height )
294
+ group . count > chosen . count ||
295
+ ( group . count === chosen . count &&
296
+ group . anchors [ 0 ] . block . height > chosen . anchors [ 0 ] . block . height )
244
297
) {
245
298
chosen = group ;
246
299
}
@@ -251,6 +304,7 @@ export class AnchorStore {
251
304
return chosen . anchors ;
252
305
}
253
306
307
+
254
308
public isStale ( version : number ) : boolean {
255
309
return version < this . staleThreshold ;
256
310
}
0 commit comments