Skip to content
This repository was archived by the owner on Mar 28, 2025. It is now read-only.

Commit 41fa332

Browse files
authored
add support for mtls (#19)
1 parent cb63911 commit 41fa332

File tree

6 files changed

+87
-20
lines changed

6 files changed

+87
-20
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/coverage/
44
/dist
55
.DS_Store
6+
tests/certs/*

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "getindexify",
3-
"version": "0.0.25",
3+
"version": "0.0.26",
44
"description": "This is the TypeScript client for interacting with the Indexify service.",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",

src/client.ts

+60-15
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
IBaseContentMetadata,
1414
IExtractedMetadata,
1515
ISchema,
16+
IMtlsConfig,
1617
} from "./types";
18+
import { Agent } from "https";
1719

1820
const DEFAULT_SERVICE_URL = "http://localhost:8900"; // Set your default service URL
1921

@@ -26,24 +28,33 @@ class IndexifyClient {
2628
constructor(
2729
serviceUrl: string = DEFAULT_SERVICE_URL,
2830
namespace: string = "default",
29-
extractionPolicies: IExtractionPolicy[]
31+
// optional mtls config
32+
extractionPolicies: IExtractionPolicy[],
33+
httpsAgent?: Agent
3034
) {
3135
this.serviceUrl = serviceUrl;
3236
this.namespace = namespace;
3337
this.extractionPolicies = extractionPolicies;
38+
3439
this.client = axios.create({
3540
baseURL: `${serviceUrl}/namespaces/${namespace}`,
41+
httpsAgent,
3642
});
3743
}
3844

3945
static async createClient({
4046
serviceUrl = DEFAULT_SERVICE_URL,
4147
namespace = "default",
48+
mtlsConfig,
4249
}: {
4350
serviceUrl?: string;
4451
namespace?: string;
52+
mtlsConfig?: IMtlsConfig;
4553
} = {}): Promise<IndexifyClient> {
46-
const response = await axios.get(`${serviceUrl}/namespaces/${namespace}`);
54+
const response = await axios.get(`${serviceUrl}/namespaces/${namespace}`, {
55+
httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }),
56+
});
57+
4758
return new IndexifyClient(
4859
serviceUrl,
4960
namespace,
@@ -66,7 +77,8 @@ class IndexifyClient {
6677
content_source: item.content_source,
6778
};
6879
}
69-
) as IExtractionPolicy[]
80+
) as IExtractionPolicy[],
81+
IndexifyClient.getHttpsAgent({ mtlsConfig })
7082
);
7183
}
7284

@@ -89,12 +101,12 @@ class IndexifyClient {
89101
throw error;
90102
}
91103
}
92-
104+
93105
private baseContentToContentMetadata = (
94106
content: IBaseContentMetadata
95107
): IContentMetadata => {
96108
let content_url: string;
97-
109+
98110
if (content.storage_url.startsWith("http")) {
99111
// if content is ingested with remote url use storage url
100112
content_url = content.storage_url;
@@ -109,33 +121,67 @@ class IndexifyClient {
109121
};
110122
};
111123

124+
static getHttpsAgent({
125+
mtlsConfig,
126+
}: {
127+
mtlsConfig?: IMtlsConfig;
128+
}): Agent | undefined {
129+
let httpsAgent = undefined;
130+
if (mtlsConfig !== undefined) {
131+
if (typeof window !== "undefined") {
132+
throw new Error(
133+
"mTLS support is not available in browser environments."
134+
);
135+
}
136+
const fs = require("fs");
137+
httpsAgent = new Agent({
138+
cert: fs.readFileSync(mtlsConfig.certPath),
139+
key: fs.readFileSync(mtlsConfig.keyPath),
140+
...(mtlsConfig.caPath && { ca: fs.readFileSync(mtlsConfig.caPath) }),
141+
rejectUnauthorized: true,
142+
});
143+
}
144+
145+
return httpsAgent;
146+
}
147+
112148
async get(endpoint: string): Promise<AxiosResponse> {
113149
return this.request("GET", endpoint);
114150
}
115151

116152
static async namespaces({
117153
serviceUrl = DEFAULT_SERVICE_URL,
154+
mtlsConfig,
118155
}: {
119156
serviceUrl?: string;
157+
mtlsConfig?: IMtlsConfig;
120158
} = {}): Promise<INamespace[]> {
121-
const response = await axios.get(`${serviceUrl}/namespaces`);
159+
const response = await axios.get(`${serviceUrl}/namespaces`, {
160+
httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }),
161+
});
122162
return response.data.namespaces;
123163
}
124164

125165
static async createNamespace({
126166
namespace,
127167
extraction_policies,
128168
labels,
169+
mtlsConfig,
129170
}: {
130171
namespace: string;
131172
extraction_policies?: IExtractionPolicy[];
132173
labels?: Record<string, string>;
174+
mtlsConfig?: IMtlsConfig;
133175
}) {
134-
await axios.post(`${DEFAULT_SERVICE_URL}/namespaces`, {
135-
name: namespace,
136-
extraction_policies: extraction_policies ?? [],
137-
labels: labels ?? {},
138-
});
176+
await axios.post(
177+
`${DEFAULT_SERVICE_URL}/namespaces`,
178+
{
179+
name: namespace,
180+
extraction_policies: extraction_policies ?? [],
181+
labels: labels ?? {},
182+
},
183+
{ httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }) }
184+
);
139185
const client = await IndexifyClient.createClient({ namespace });
140186
return client;
141187
}
@@ -146,7 +192,7 @@ class IndexifyClient {
146192
}
147193

148194
async extractors(): Promise<Extractor[]> {
149-
const response = await axios.get(`${this.serviceUrl}/extractors`);
195+
const response = await this.client.get(`${this.serviceUrl}/extractors`);
150196
const extractorsData = response.data.extractors as IExtractor[];
151197
return extractorsData.map((data) => new Extractor(data));
152198
}
@@ -248,12 +294,11 @@ class IndexifyClient {
248294
}
249295

250296
async downloadContent<T>(id: string): Promise<T> {
251-
const url = `${this.serviceUrl}/namespaces/${this.namespace}/content/${id}/download`;
252297
try {
253-
const response = await axios.get<T>(url);
298+
const response = await this.client.get(`content/${id}/download`);
254299
return response.data;
255300
} catch (error) {
256-
throw new Error(`Failed to download content ${url}: ${error}`);
301+
throw new Error(`Failed to download content ${id}: ${error}`);
257302
}
258303
}
259304

src/types.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export interface IExtractedMetadata {
5555
}
5656

5757
export interface IExtractionPolicy {
58-
id?: string
58+
id?: string;
5959
extractor: string;
6060
name: string;
6161
labels_eq?: string;
@@ -92,3 +92,9 @@ export interface ISearchIndexResponse {
9292
export interface IAddExtractorPolicyResponse {
9393
index_names: string[];
9494
}
95+
96+
export interface IMtlsConfig {
97+
certPath: string;
98+
keyPath: string;
99+
caPath?: string; // Optional, only if using a custom CA
100+
}

tests/client.test.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ test("Search", async () => {
7878
const client = await IndexifyClient.createNamespace({
7979
namespace: "testsearch",
8080
});
81-
console.log('got namespace?', client.namespace)
81+
8282
const resp = await client.addExtractionPolicy(policy);
8383
expect(resp.index_names.length).toBe(1);
8484

@@ -162,3 +162,18 @@ test("Get Extraction Policies", async () => {
162162
const policies = await client.getExtractionPolicies();
163163
expect(policies.length).toBe(1);
164164
});
165+
166+
// test.only("MTLS", async () => {
167+
// const fs = require("fs")
168+
// const https = require("https")
169+
// const axios = require("axios")
170+
171+
// const client = await IndexifyClient.createClient({
172+
// serviceUrl: "mtls url",
173+
// mtlsConfig:{
174+
// certPath: "tests/certs/client.crt",
175+
// keyPath: "tests/certs/client.key"
176+
// }
177+
// })
178+
// const content = await client.getContent()
179+
// });

0 commit comments

Comments
 (0)