@hahnpro/hpc-api 5.2.8 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -35,5 +35,7 @@ export declare class API {
35
35
  users: UserService;
36
36
  vault: VaultService;
37
37
  notifications: NotificationService;
38
- constructor(httpClient?: HttpClient);
38
+ constructor(httpClient?: HttpClient, context?: {
39
+ tokenSubject?: string;
40
+ });
39
41
  }
package/dist/api.js CHANGED
@@ -20,7 +20,7 @@ const label_service_1 = require("./label.service");
20
20
  const vault_service_1 = require("./vault.service");
21
21
  const notification_service_1 = require("./notification.service");
22
22
  class API {
23
- constructor(httpClient) {
23
+ constructor(httpClient, context) {
24
24
  this.httpClient = httpClient;
25
25
  if (!httpClient) {
26
26
  const normalizePath = (value = '', defaultValue = '') => value.replace(/(?:^\/+)|(?:\/+$)/g, '') || defaultValue;
@@ -38,7 +38,7 @@ class API {
38
38
  if (!secret) {
39
39
  throw new Error('"API_BASE_URL", "API_USER", "AUTH_REALM" and "AUTH_SECRET" environment variables must be set');
40
40
  }
41
- this.httpClient = new http_service_1.HttpClient(apiUrl, authUrl, realm, client, secret);
41
+ this.httpClient = new http_service_1.HttpClient(apiUrl, authUrl, realm, client, secret, context === null || context === void 0 ? void 0 : context.tokenSubject);
42
42
  }
43
43
  this.assets = new asset_service_1.AssetService(this.httpClient);
44
44
  this.assetTypes = new assettypes_service_1.AssetTypesService(this.httpClient);
@@ -1,22 +1,25 @@
1
1
  import { AxiosInstance, AxiosRequestConfig, Method } from 'axios';
2
2
  import EventSource from 'eventsource';
3
3
  import { Queue } from './Queue';
4
+ import { TokenSet } from './token-set';
4
5
  export declare class HttpClient {
5
6
  protected readonly baseURL: string;
6
7
  protected readonly authBaseURL: string;
7
8
  protected readonly realm: string;
8
9
  protected readonly clientId: string;
9
10
  protected readonly clientSecret: string;
11
+ protected readonly tokenSubject?: string;
10
12
  protected readonly axiosInstance: AxiosInstance;
11
13
  protected readonly authAxiosInstance: AxiosInstance;
12
14
  protected readonly requestQueue: Queue;
13
15
  private tokenSet;
16
+ private exchangedTokenSet;
14
17
  eventSourcesMap: Map<string, {
15
18
  eventSource: EventSource;
16
19
  listener: (event: MessageEvent) => void;
17
20
  errListener: (event: MessageEvent) => void;
18
21
  }>;
19
- constructor(baseURL: string, authBaseURL: string, realm: string, clientId: string, clientSecret: string);
22
+ constructor(baseURL: string, authBaseURL: string, realm: string, clientId: string, clientSecret: string, tokenSubject?: string);
20
23
  getQueueStats: () => {
21
24
  peak: number;
22
25
  pending: number;
@@ -34,7 +37,8 @@ export declare class HttpClient {
34
37
  getAccessToken: (forceRefresh?: boolean) => Promise<string>;
35
38
  protected validateIssuer(issuer: Issuer): Issuer;
36
39
  protected discoverIssuer(uri: string): Promise<Issuer>;
37
- protected requestAccessToken(): Promise<string>;
40
+ protected requestAccessToken(additionalOpts?: {}): Promise<TokenSet>;
41
+ protected exchangeAccessToken(accessToken: string): Promise<TokenSet>;
38
42
  }
39
43
  interface Issuer {
40
44
  issuer: string;
@@ -10,12 +10,13 @@ const uuid_1 = require("uuid");
10
10
  const Queue_1 = require("./Queue");
11
11
  const token_set_1 = require("./token-set");
12
12
  class HttpClient {
13
- constructor(baseURL, authBaseURL, realm, clientId, clientSecret) {
13
+ constructor(baseURL, authBaseURL, realm, clientId, clientSecret, tokenSubject) {
14
14
  this.baseURL = baseURL;
15
15
  this.authBaseURL = authBaseURL;
16
16
  this.realm = realm;
17
17
  this.clientId = clientId;
18
18
  this.clientSecret = clientSecret;
19
+ this.tokenSubject = tokenSubject;
19
20
  this.eventSourcesMap = new Map();
20
21
  this.getQueueStats = () => { var _a; return (_a = this.requestQueue) === null || _a === void 0 ? void 0 : _a.getStats(); };
21
22
  this.delete = (url, config) => this.request('DELETE', url, config);
@@ -34,10 +35,23 @@ class HttpClient {
34
35
  }));
35
36
  };
36
37
  this.getAccessToken = (...args_1) => tslib_1.__awaiter(this, [...args_1], void 0, function* (forceRefresh = false) {
38
+ let accessToken;
37
39
  if (forceRefresh || !this.tokenSet || this.tokenSet.isExpired()) {
38
- return this.requestAccessToken();
40
+ this.tokenSet = yield this.requestAccessToken();
41
+ accessToken = this.tokenSet.accessToken;
42
+ }
43
+ else {
44
+ accessToken = this.tokenSet.accessToken;
45
+ }
46
+ if (this.tokenSubject) {
47
+ if (forceRefresh || !this.exchangedTokenSet || this.exchangedTokenSet.isExpired()) {
48
+ this.exchangedTokenSet = yield this.exchangeAccessToken(accessToken);
49
+ }
50
+ return this.exchangedTokenSet.accessToken;
51
+ }
52
+ else {
53
+ return accessToken;
39
54
  }
40
- return this.tokenSet.accessToken;
41
55
  });
42
56
  this.axiosInstance = axios_1.default.create({ baseURL, timeout: 60000 });
43
57
  this.authAxiosInstance = axios_1.default.create({ baseURL: authBaseURL || baseURL, timeout: 10000 });
@@ -95,7 +109,7 @@ class HttpClient {
95
109
  });
96
110
  }
97
111
  requestAccessToken() {
98
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
112
+ return tslib_1.__awaiter(this, arguments, void 0, function* (additionalOpts = {}) {
99
113
  var _a, _b;
100
114
  const issuer = yield this.discoverIssuer(`${this.authBaseURL}/realms/${this.realm}`);
101
115
  const timestamp = Date.now() / 1000;
@@ -116,23 +130,32 @@ class HttpClient {
116
130
  const assertion = yield new jose_1.CompactSign(Buffer.from(JSON.stringify(assertionPayload)))
117
131
  .setProtectedHeader({ alg })
118
132
  .sign(new TextEncoder().encode(this.clientSecret));
119
- const opts = {
120
- client_id: this.clientId,
121
- client_assertion: assertion,
122
- client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
123
- grant_type: 'client_credentials',
124
- };
133
+ const opts = Object.assign({ client_id: this.clientId, client_assertion: assertion, client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', grant_type: 'client_credentials' }, additionalOpts);
125
134
  const authResponse = yield this.authAxiosInstance.post(issuer.token_endpoint, (0, querystring_1.stringify)(opts), {
126
135
  headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },
127
136
  });
128
137
  if (((_b = authResponse === null || authResponse === void 0 ? void 0 : authResponse.data) === null || _b === void 0 ? void 0 : _b.access_token) && authResponse.data.expires_in) {
129
- this.tokenSet = new token_set_1.TokenSet(authResponse.data.access_token, authResponse.data.expires_in);
130
- return authResponse.data.access_token;
138
+ return new token_set_1.TokenSet(authResponse.data.access_token, authResponse.data.expires_in);
131
139
  }
132
140
  else {
133
141
  throw new Error('Invalid access token received');
134
142
  }
135
143
  });
136
144
  }
145
+ exchangeAccessToken(accessToken) {
146
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
147
+ if (!accessToken || !this.tokenSubject) {
148
+ throw new Error('Could not exchange access token');
149
+ }
150
+ const opts = {
151
+ grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
152
+ subject_token: accessToken,
153
+ audience: this.clientId,
154
+ requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',
155
+ requested_subject: this.tokenSubject,
156
+ };
157
+ return this.requestAccessToken(opts);
158
+ });
159
+ }
137
160
  }
138
161
  exports.HttpClient = HttpClient;
@@ -5,6 +5,7 @@ export interface ResourceReference {
5
5
  }
6
6
  export interface Resource {
7
7
  id: string;
8
+ owner?: Owner;
8
9
  name: string;
9
10
  readPermissions: string[];
10
11
  readWritePermissions: string[];
@@ -16,4 +17,16 @@ export interface Resource {
16
17
  updatedAt?: string | Date;
17
18
  deletedAt?: string | Date;
18
19
  revision?: string;
20
+ createdBy?: Author;
21
+ updatedBy?: Author;
22
+ }
23
+ export interface Author {
24
+ id: string;
25
+ username: string;
26
+ impersonatorId?: string;
27
+ impersonatorUsername?: string;
28
+ }
29
+ export interface Owner {
30
+ id: string;
31
+ type: 'org' | 'user';
19
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hahnpro/hpc-api",
3
- "version": "5.2.8",
3
+ "version": "5.3.0",
4
4
  "description": "Module for easy access to the HahnPRO API",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -27,7 +27,7 @@
27
27
  "axios": "1.7.4",
28
28
  "eventsource": "2.0.2",
29
29
  "form-data": "4.0.0",
30
- "jose": "5.6.3",
30
+ "jose": "5.7.0",
31
31
  "jwt-decode": "4.0.0",
32
32
  "p-queue": "6.6.2",
33
33
  "ts-mixer": "6.0.4",