ipfs / helia

An implementation of IPFS in TypeScript
https://helia.io
Other
970 stars 106 forks source link

@helia/block-brokers should support http headers being passed #659

Open pcfreak30 opened 1 month ago

pcfreak30 commented 1 month ago

Hello,

I have been implementing helia into a new IPFS pinning service I will be launching EOY (paid service, but FOSS code) (uses the ipfs pinning spec). One barrier I ran into that I had to fork and create a pnpm patch is accessing the downloads on the trustless gateway behind a JWT.

I would like to request that my hack be used as a guide point for implementing support so I can stop needing to patch helia :P.

To be clear, I am currently offering a trustless gateway API, but it requires a JWT.

Kudos

Subject: [PATCH] wip
---
Index: packages/block-brokers/src/trustless-gateway/broker.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/packages/block-brokers/src/trustless-gateway/broker.ts b/packages/block-brokers/src/trustless-gateway/broker.ts
--- a/packages/block-brokers/src/trustless-gateway/broker.ts    (revision ac4bdb8a73cab23500221340830969552a1d8db6)
+++ b/packages/block-brokers/src/trustless-gateway/broker.ts    (revision 1955f39d9f32960978d66d9782282acb4478b3f4)
@@ -22,6 +22,8 @@
    * @default false
    */
   allowLocal?: boolean
+
+  headers?: Record<string, string>
 }

 /**
@@ -31,6 +33,7 @@
 export class TrustlessGatewayBlockBroker implements BlockBroker<TrustlessGatewayGetBlockProgressEvents> {
   private readonly allowInsecure: boolean
   private readonly allowLocal: boolean
+  private readonly headers?: Record<string, string>
   private readonly routing: Routing
   private readonly log: Logger
   private readonly logger: ComponentLogger
@@ -41,12 +44,13 @@
     this.routing = components.routing
     this.allowInsecure = init.allowInsecure ?? DEFAULT_ALLOW_INSECURE
     this.allowLocal = init.allowLocal ?? DEFAULT_ALLOW_LOCAL
+    this.headers = init.headers ?? {}
   }

   async retrieve (cid: CID, options: BlockRetrievalOptions<TrustlessGatewayGetBlockProgressEvents> = {}): Promise<Uint8Array> {
     const aggregateErrors: Error[] = []

-    for await (const gateway of findHttpGatewayProviders(cid, this.routing, this.logger, this.allowInsecure, this.allowLocal, options)) {
+    for await (const gateway of findHttpGatewayProviders(cid, this.routing, this.logger, this.allowInsecure, this.allowLocal, this.headers,  options)) {
       this.log('getting block for %c from %s', cid, gateway.url)

       try {
@@ -93,7 +97,11 @@
     }, {
       ...options,
       allowLocal: this.allowLocal,
-      allowInsecure: this.allowInsecure
+      allowInsecure: this.allowInsecure,
+      headers: {
+        ...this.headers,
+        ...options.headers
+      }
     })
   }
 }
Index: packages/block-brokers/src/trustless-gateway/index.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/packages/block-brokers/src/trustless-gateway/index.ts b/packages/block-brokers/src/trustless-gateway/index.ts
--- a/packages/block-brokers/src/trustless-gateway/index.ts (revision ac4bdb8a73cab23500221340830969552a1d8db6)
+++ b/packages/block-brokers/src/trustless-gateway/index.ts (revision 1955f39d9f32960978d66d9782282acb4478b3f4)
@@ -25,6 +25,8 @@
    * @default false
    */
   allowLocal?: boolean
+
+  headers?: Record<string, string>
 }

 export interface TrustlessGatewayComponents {
Index: packages/block-brokers/src/trustless-gateway/session.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/packages/block-brokers/src/trustless-gateway/session.ts b/packages/block-brokers/src/trustless-gateway/session.ts
--- a/packages/block-brokers/src/trustless-gateway/session.ts   (revision ac4bdb8a73cab23500221340830969552a1d8db6)
+++ b/packages/block-brokers/src/trustless-gateway/session.ts   (revision 1955f39d9f32960978d66d9782282acb4478b3f4)
@@ -18,6 +18,7 @@
   private readonly routing: Routing
   private readonly allowInsecure: boolean
   private readonly allowLocal: boolean
+  private readonly headers?: Record<string, string>

   constructor (components: TrustlessGatewaySessionComponents, init: CreateTrustlessGatewaySessionOptions) {
     super(components, {
@@ -28,6 +29,7 @@
     this.routing = components.routing
     this.allowInsecure = init.allowInsecure ?? DEFAULT_ALLOW_INSECURE
     this.allowLocal = init.allowLocal ?? DEFAULT_ALLOW_LOCAL
+    this.headers = init.headers ?? {}
   }

   async queryProvider (cid: CID, provider: TrustlessGateway, options: BlockRetrievalOptions): Promise<Uint8Array> {
@@ -41,8 +43,8 @@
     return block
   }

-  async * findNewProviders (cid: CID, options: AbortOptions = {}): AsyncGenerator<TrustlessGateway> {
-    yield * findHttpGatewayProviders(cid, this.routing, this.logger, this.allowInsecure, this.allowLocal, options)
+  async * findNewProviders (cid: CID, options: AbortOptions = {}, headers: Record<string, string> = {}): AsyncGenerator<TrustlessGateway> {
+    yield * findHttpGatewayProviders(cid, this.routing, this.logger, this.allowInsecure, this.allowLocal, this.headers, options)
   }

   toEvictionKey (provider: TrustlessGateway): Uint8Array | string {
Index: packages/block-brokers/src/trustless-gateway/trustless-gateway.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/packages/block-brokers/src/trustless-gateway/trustless-gateway.ts b/packages/block-brokers/src/trustless-gateway/trustless-gateway.ts
--- a/packages/block-brokers/src/trustless-gateway/trustless-gateway.ts (revision ac4bdb8a73cab23500221340830969552a1d8db6)
+++ b/packages/block-brokers/src/trustless-gateway/trustless-gateway.ts (revision 1955f39d9f32960978d66d9782282acb4478b3f4)
@@ -54,9 +54,11 @@
   readonly #pendingResponses = new Map<string, Promise<Uint8Array>>()

   private readonly log: Logger
+  private readonly headers: Record<string, string>

-  constructor (url: URL | string, logger: ComponentLogger) {
+  constructor (url: URL | string, headers: Record<string, string>, logger: ComponentLogger) {
     this.url = url instanceof URL ? url : new URL(url)
+    this.headers = headers
     this.log = logger.forComponent(`helia:trustless-gateway-block-broker:${this.url.hostname}`)
   }

@@ -106,7 +108,8 @@
         pendingResponse = fetch(gwUrl.toString(), {
           signal: innerController.signal,
           headers: {
-            Accept: 'application/vnd.ipld.raw'
+            Accept: 'application/vnd.ipld.raw',
+            ...this.headers
           },
           cache: 'force-cache'
         }).then(async (res) => {
Index: packages/block-brokers/src/trustless-gateway/utils.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/packages/block-brokers/src/trustless-gateway/utils.ts b/packages/block-brokers/src/trustless-gateway/utils.ts
--- a/packages/block-brokers/src/trustless-gateway/utils.ts (revision ac4bdb8a73cab23500221340830969552a1d8db6)
+++ b/packages/block-brokers/src/trustless-gateway/utils.ts (revision 1955f39d9f32960978d66d9782282acb4478b3f4)
@@ -33,7 +33,7 @@
   })
 }

-export async function * findHttpGatewayProviders (cid: CID, routing: Routing, logger: ComponentLogger, allowInsecure: boolean, allowLocal: boolean, options?: AbortOptions): AsyncGenerator<TrustlessGateway> {
+export async function * findHttpGatewayProviders (cid: CID, routing: Routing, logger: ComponentLogger, allowInsecure: boolean, allowLocal: boolean, headers: Record<string, string> = {}, options: AbortOptions = {}): AsyncGenerator<TrustlessGateway> {
   for await (const provider of routing.findProviders(cid, options)) {
     // require http(s) addresses
     const httpAddresses = filterNonHTTPMultiaddrs(provider.multiaddrs, allowInsecure, allowLocal)
@@ -48,6 +48,6 @@
     // etc
     const uri = multiaddrToUri(httpAddresses[0])

-    yield new TrustlessGateway(uri, logger)
+    yield new TrustlessGateway(uri, headers, logger)
   }
 }
Index: packages/block-brokers/test/trustless-gateway.spec.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/packages/block-brokers/test/trustless-gateway.spec.ts b/packages/block-brokers/test/trustless-gateway.spec.ts
--- a/packages/block-brokers/test/trustless-gateway.spec.ts (revision ac4bdb8a73cab23500221340830969552a1d8db6)
+++ b/packages/block-brokers/test/trustless-gateway.spec.ts (revision 1955f39d9f32960978d66d9782282acb4478b3f4)
@@ -148,7 +148,7 @@
     if (process.env.TRUSTLESS_GATEWAY == null) {
       return this.skip()
     }
-    const trustlessGateway = new TrustlessGateway(process.env.TRUSTLESS_GATEWAY, defaultLogger())
+    const trustlessGateway = new TrustlessGateway(process.env.TRUSTLESS_GATEWAY, {}, defaultLogger())

     // Call getRawBlock multiple times with the same CID
     const promises = Array.from({ length: 10 }, async () => trustlessGateway.getRawBlock(cid))