From ff03829b8cee86c34445b2c0a885e2d99b396fe6 Mon Sep 17 00:00:00 2001 From: Alexander Shevtsov Date: Fri, 27 Jun 2025 15:59:29 +0200 Subject: [PATCH 1/2] fix of for local anchors file --- bin/common.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/bin/common.ts b/bin/common.ts index e9b362b..21dfdcd 100644 --- a/bin/common.ts +++ b/bin/common.ts @@ -56,16 +56,19 @@ export async function nodeOpts(opts: MainOptions): Promise { export async function anchorFromOpts(opts: MainOptions): Promise { const localAnchors = opts.localAnchors || process.env.FABRIC_LOCAL_ANCHORS; - const remoteAnchors = - opts.remoteAnchors || - (process.env.FABRIC_REMOTE_ANCHORS - ? process.env.FABRIC_REMOTE_ANCHORS.split(',') - : ['http://127.0.0.1:7225/root-anchors.json']); + const remoteAnchors = opts.remoteAnchors || (process.env.FABRIC_REMOTE_ANCHORS ? process.env.FABRIC_REMOTE_ANCHORS.split(',') : undefined); - return AnchorStore.create({ - localPath: localAnchors, - remoteUrls: remoteAnchors, - }); + const updateOptions: any = {}; + + if (localAnchors) { + updateOptions.localPath = localAnchors; + } else if (remoteAnchors) { + updateOptions.remoteUrls = remoteAnchors; + } else { + updateOptions.remoteUrls = ['http://127.0.0.1:7225/root-anchors.json']; + } + + return AnchorStore.create(updateOptions); } export function joinHostPort(address: Address | null): string { From 1e609d05c185005b737859fe9baf5325fd83f308 Mon Sep 17 00:00:00 2001 From: Alexander Shevtsov Date: Wed, 16 Jul 2025 17:37:01 +0200 Subject: [PATCH 2/2] added basic auth support --- anchor.ts | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/anchor.ts b/anchor.ts index ac87dd1..ea562e4 100644 --- a/anchor.ts +++ b/anchor.ts @@ -12,11 +12,17 @@ interface Anchor { }; } +interface BasicAuthConfig { + username: string; + password: string; +} + interface UpdateOptions { localPath?: string; // Local file remoteUrls?: string[]; // Remote endpoints to fetch anchor file staticAnchors?: Anchor[]; // Use the following static anchors checkIntervalMs?: number; // Periodic refresh + basicAuth?: BasicAuthConfig; } export class AnchorStore { @@ -198,12 +204,59 @@ export class AnchorStore { return null; } + private extractAuthFromUrl(url: string): { username: string; password: string } | null { + try { + const urlObj = new URL(url); + if (urlObj.username && urlObj.password) { + return { + username: decodeURIComponent(urlObj.username), + password: decodeURIComponent(urlObj.password) + }; + } + } catch (err) { + log(`Invalid URL format: ${url}`); + } + return null; + } + + private cleanUrl(url: string): string { + try { + const urlObj = new URL(url); + urlObj.username = ''; + urlObj.password = ''; + return urlObj.toString(); + } catch (err) { + log(`Invalid URL format: ${url}`); + return url; + } + } + + private createAuthHeaders(url: string): HeadersInit { + const headers: HeadersInit = {}; + const authFromUrl = this.extractAuthFromUrl(url); + if (authFromUrl) { + const credentials = Buffer.from(`${authFromUrl.username}:${authFromUrl.password}`).toString('base64'); + headers['Authorization'] = `Basic ${credentials}`; + } else if (this.options.basicAuth) { + const { username, password } = this.options.basicAuth; + const credentials = Buffer.from(`${username}:${password}`).toString('base64'); + headers['Authorization'] = `Basic ${credentials}`; + } + + return headers; + } + private async fetchAnchorsFromRemotes(remoteUrls: string[]): Promise { const responses = await Promise.all( remoteUrls.map(async url => { log(`Fetching anchors from: ${url}`); try { - const res = await fetch(url); + const authHeaders = this.createAuthHeaders(url); + const cleanUrl = this.cleanUrl(url); + + const res = await fetch(cleanUrl, { + headers: authHeaders + }); if (!res.ok) { throw new Error(`Status: ${res.status}`); } @@ -238,9 +291,9 @@ export class AnchorStore { for (const group of groups.values()) { if ( !chosen || - group.count > chosen.count || - (group.count === chosen.count && - group.anchors[0].block.height > chosen.anchors[0].block.height) + group.count > chosen.count || + (group.count === chosen.count && + group.anchors[0].block.height > chosen.anchors[0].block.height) ) { chosen = group; } @@ -251,6 +304,7 @@ export class AnchorStore { return chosen.anchors; } + public isStale(version: number): boolean { return version < this.staleThreshold; }