Skip to content

Commit a7b94be

Browse files
committed
fix token expiry logic
1 parent d746324 commit a7b94be

4 files changed

Lines changed: 88 additions & 35 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ http.get("http://my-service.namespace/path", { agent }, (res) => {
4040

4141
## API
4242

43-
### `new CodezeroAgent(orgID: string, orgAPIKey: string, spaceID: string)`
43+
### `new CodezeroAgent({ orgID: string, orgAPIKey: string, spaceID: string })`
4444

4545
Returns implementation of an `http.Agent` that connects to the Teamspace with the given `spaceID`.
4646

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@c6o/codezero-agent",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"description": "Codezero http.Agent implementation for NodeJS",
55
"main": "dist/index.mjs",
66
"types": "dist/index.d.mts",

src/index.mts

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,34 @@ interface SpaceCredentials {
1010
cert: string;
1111
}
1212

13+
type CodezeroParams = {
14+
orgID?: string;
15+
orgApiKey?: string;
16+
spaceID?: string;
17+
};
18+
1319
export class CodezeroAgent extends HttpsProxyAgent<string> {
1420
private _credentials: SpaceCredentials | null = null;
15-
private _hubServerBaseUrl: string = 'https://hub.codezero.io';
21+
private _hubServerBaseUrl: string = "https://hub.codezero.io";
22+
private orgID: string;
23+
private orgApiKey: string;
24+
private spaceID: string;
25+
26+
constructor(params: CodezeroParams = {}) {
27+
const orgID = params.orgID || process.env.CZ_ORG_ID;
28+
const orgApiKey = params.orgApiKey || process.env.CZ_ORG_API_KEY;
29+
const spaceID = params.spaceID || process.env.CZ_SPACE_ID;
1630

17-
constructor(
18-
private orgID = process.env.CZ_ORG_ID,
19-
private orgApiKey = process.env.CZ_ORG_API_KEY,
20-
private spaceID = process.env.CZ_SPACE_ID
21-
) {
2231
if (!orgID || !orgApiKey || !spaceID) {
2332
throw new Error("Missing CZ_ORG_ID, CZ_ORG_API_KEY or CZ_SPACE_ID");
2433
}
34+
2535
super("https://127.0.0.1");
2636

37+
this.orgID = orgID;
38+
this.orgApiKey = orgApiKey;
39+
this.spaceID = spaceID;
40+
2741
if (process.env.CZ_HUB_SERVER_BASE_URL) {
2842
this._hubServerBaseUrl = process.env.CZ_HUB_SERVER_BASE_URL!;
2943
}
@@ -43,35 +57,38 @@ export class CodezeroAgent extends HttpsProxyAgent<string> {
4357
return super.connect(req, opts);
4458
}
4559
private async getSpaceCredentials(): Promise<SpaceCredentials> {
46-
if (!this._credentials || this.tokenExpired(this._credentials.token)) {
47-
const spaceResponse = await fetch(
48-
`${this._hubServerBaseUrl}/api/c6o/connect/c6oapi.v1.C6OService/GetSpaceConnection`,
49-
{
50-
method: "POST",
51-
headers: {
52-
Authorization: `${this.orgID}:${this.orgApiKey}`,
53-
"Content-Type": "application/json",
54-
},
55-
body: JSON.stringify({
56-
spaceId: this.spaceID,
57-
}),
58-
}
59-
);
60-
const response = (await spaceResponse.json()) as any;
60+
if (this._credentials && !this.tokenExpired(this._credentials.token)) {
61+
return this._credentials;
62+
}
6163

62-
if (!spaceResponse.ok) {
63-
throw new Error(response.message);
64+
const spaceResponse = await fetch(
65+
`${this._hubServerBaseUrl}/api/c6o/connect/c6oapi.v1.C6OService/GetSpaceConnection`,
66+
{
67+
method: "POST",
68+
headers: {
69+
Authorization: `${this.orgID}:${this.orgApiKey}`,
70+
"Content-Type": "application/json",
71+
},
72+
body: JSON.stringify({
73+
spaceId: this.spaceID,
74+
}),
6475
}
65-
this._credentials = response as SpaceCredentials;
76+
);
77+
const response = (await spaceResponse.json()) as any;
78+
79+
if (!spaceResponse.ok) {
80+
throw new Error(response.message);
6681
}
82+
this._credentials = response as SpaceCredentials;
6783

6884
return this._credentials;
6985
}
86+
7087
private tokenExpired(token: string): boolean {
7188
const [, payload] = token.split(".");
7289
if (!payload) return true;
7390

7491
const decoded = JSON.parse(Buffer.from(payload, "base64").toString());
75-
return decoded.exp - 2 * 60 * 1000 < Date.now() / 1000;
92+
return decoded.exp - 2 * 60 < Date.now() / 1000;
7693
}
7794
}

test/test.mts

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
1+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
22
import { Server, createServer } from 'http';
33
import { createServer as createSSLServer } from 'https';
44
import { readFileSync } from 'fs';
@@ -10,27 +10,41 @@ import { CodezeroAgent } from '../src/index.mts';
1010
describe('CodezeroAgent', () => {
1111
describe ('constructor', () => {
1212
it('should not throw given org id, org api key and space id', () => {
13-
expect(() => new CodezeroAgent("orgId", "orgApiKey", "spaceId")).not.toThrow("Missing CZ_ORG_ID, CZ_ORG_API_KEY or CZ_SPACE_ID");
13+
expect(() => new CodezeroAgent({orgID: "orgId", orgApiKey: "orgApiKey", spaceID: "spaceId"})).not.toThrow("Missing CZ_ORG_ID, CZ_ORG_API_KEY or CZ_SPACE_ID");
1414
});
1515

1616
it('should throw if org id, org api key or space id are missing', () => {
17-
expect(() => new CodezeroAgent("1", "2")).toThrow("Missing CZ_ORG_ID, CZ_ORG_API_KEY or CZ_SPACE_ID");
17+
expect(() => new CodezeroAgent({orgID: "orgId", orgApiKey: "orgApiKey"})).toThrow("Missing CZ_ORG_ID, CZ_ORG_API_KEY or CZ_SPACE_ID");
1818
});
1919
});
2020

2121
describe('node-fetch', () => {
2222
let hubServer: Server;
2323
let hubServerUrl: URL;
24+
let receivedAuth: string;
25+
let hubRequestCount = 0;
2426

2527
let proxy: ProxyServer;
2628
let proxyUrl: URL;
2729

2830
let targetServer: Server;
2931
let targetServerUrl: URL;
32+
let spaceCreds: any
33+
34+
const createToken = (offsetSeconds: number) => {
35+
const time = Date.now() / 1000 + offsetSeconds;
36+
const payload = Buffer.from(JSON.stringify({ exp: time })).toString('base64');
37+
return `header.${payload}`;
38+
}
3039

31-
beforeAll(async() => {
32-
hubServer = createServer((_req, res) => {
33-
res.end(JSON.stringify({host: '127.0.0.1', token: 'token', cert: readFileSync(`${__dirname}/server.crt`).toString()}));
40+
beforeEach(async() => {
41+
spaceCreds = {host: '127.0.0.1', token: createToken(3*60), cert: readFileSync(`${__dirname}/server.crt`).toString()};
42+
43+
hubRequestCount = 0;
44+
hubServer = createServer((req, res) => {
45+
hubRequestCount++;
46+
receivedAuth = req.headers.authorization!;
47+
res.end(JSON.stringify(spaceCreds));
3448
});
3549
hubServerUrl = await listen(hubServer);
3650
process.env.CZ_HUB_SERVER_BASE_URL = hubServerUrl.href;
@@ -50,7 +64,7 @@ describe('CodezeroAgent', () => {
5064
targetServerUrl = await listen(targetServer);
5165
})
5266

53-
afterAll(() => {
67+
afterEach(() => {
5468
hubServer.close();
5569
proxy.close();
5670
targetServer.close();
@@ -59,11 +73,33 @@ describe('CodezeroAgent', () => {
5973
});
6074

6175
it('should forward fetch requests via a proxy', async () => {
62-
const agent = new CodezeroAgent("orgId", "orgApiKey", "spaceId");
76+
const agent = new CodezeroAgent({orgID: "orgId", orgApiKey: "orgApiKey", spaceID: "spaceId"});
6377
const response = await fetch(targetServerUrl.href, { agent });
6478

6579
expect(response.status).toBe(200);
6680
expect(await response.text()).toBe('Hello!');
81+
82+
expect(receivedAuth).toBe('orgId:orgApiKey');
83+
});
84+
85+
it('should cache credentials in the agent instance', async () => {
86+
const agent = new CodezeroAgent({orgID: "orgId", orgApiKey: "orgApiKey", spaceID: "spaceId"});
87+
await fetch(targetServerUrl.href, { agent });
88+
await fetch(targetServerUrl.href, { agent });
89+
90+
expect(hubRequestCount).toBe(1);
91+
});
92+
93+
it('should refetch credentials if token is expired', async () => {
94+
const agent = new CodezeroAgent({orgID: "orgId", orgApiKey: "orgApiKey", spaceID: "spaceId"});
95+
96+
await fetch(targetServerUrl.href, { agent });
97+
expect(hubRequestCount).toBe(1);
98+
99+
agent['_credentials']!['token'] = createToken(-3*60);
100+
await fetch(targetServerUrl.href, { agent });
101+
102+
expect(hubRequestCount).toBe(2);
67103
});
68104
});
69105
});

0 commit comments

Comments
 (0)