zavadil-ts-common 1.2.40 → 1.2.42

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.
@@ -8,15 +8,16 @@ export type ServerOAuthInfoPayload = {
8
8
  oauthServerUrl: string;
9
9
  version: string;
10
10
  };
11
- export declare class RestClientWithOAuth extends RestClient {
11
+ export declare class RestClientWithOAuth extends RestClient implements OAuthIdTokenProvider {
12
12
  private insecureClient;
13
13
  private freshIdTokenProvider;
14
14
  private tokenManager;
15
15
  private serverInfo;
16
16
  private defaultPrivilege;
17
17
  constructor(url: string, freshIdTokenProvider?: OAuthIdTokenProvider, defaultPrivilege?: string);
18
+ getIdToken(): Promise<IdTokenPayload>;
18
19
  /**
19
- * Attempt to get ID token from the provider, this will trigger redirect to login screen in case of the default provider
20
+ * Attempt to get ID token from token manager
20
21
  */
21
22
  initialize(): Promise<any>;
22
23
  logout(): Promise<any>;
@@ -0,0 +1,6 @@
1
+ import { TokenResponsePayloadBase } from "../oauth";
2
+ export declare class OAuthUtil {
3
+ static isValidToken(token?: TokenResponsePayloadBase | null): boolean;
4
+ static isTokenExpired(token?: TokenResponsePayloadBase | null): boolean;
5
+ static isTokenReadyForRefresh(token?: TokenResponsePayloadBase | null): boolean;
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zavadil-ts-common",
3
- "version": "1.2.40",
3
+ "version": "1.2.42",
4
4
  "description": "Common types and components for Typescript UI apps.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -1,15 +1,12 @@
1
1
  import {AccessTokenPayload, IdTokenPayload, OAuthRestClient} from "./OAuthRestClient";
2
- import {EventManager} from "../component";
3
- import {StringUtil} from "../util";
4
2
  import {OAuthIdTokenProvider} from "./tokenprovider/OAuthIdTokenProvider";
3
+ import {OAuthUtil} from "../util/OAuthUtil";
5
4
 
6
5
  /**
7
6
  * Manages refresh of id and access tokens.
8
7
  */
9
8
  export class OAuthTokenManager implements OAuthIdTokenProvider {
10
9
 
11
- private eventManager: EventManager = new EventManager();
12
-
13
10
  oAuthServer: OAuthRestClient;
14
11
 
15
12
  audience: string;
@@ -27,48 +24,22 @@ export class OAuthTokenManager implements OAuthIdTokenProvider {
27
24
  this.accessTokens = new Map<string, AccessTokenPayload>();
28
25
  }
29
26
 
30
- addIdTokenChangedHandler(handler: (t: IdTokenPayload) => any) {
31
- this.eventManager.addEventListener('id-token-changed', handler);
32
- }
33
-
34
- removeIdTokenChangedHandler(handler: (t: IdTokenPayload) => any) {
35
- this.eventManager.removeEventListener('id-token-changed', handler);
36
- }
37
-
38
- isTokenExpired(expires?: Date | null): boolean {
39
- if (expires === undefined || expires === null) return false;
40
- return (expires < new Date());
41
- }
42
-
43
- isTokenReadyForRefresh(issuedAt: Date, expires?: Date | null): boolean {
44
- if (expires === undefined || expires === null) return false;
45
- const middle = new Date((expires.getTime() + issuedAt.getTime()) / 2);
46
- const now = new Date();
47
- return (middle < now);
48
- }
49
-
50
- isValidIdToken(idToken?: IdTokenPayload): boolean {
51
- return idToken !== undefined && StringUtil.notEmpty(idToken.token) && !this.isTokenExpired(idToken.expires);
52
- }
53
-
54
27
  hasValidIdToken(): boolean {
55
- return this.isValidIdToken(this.idToken);
56
- }
57
-
58
- isValidAccessToken(accessToken?: AccessTokenPayload): boolean {
59
- return accessToken !== undefined && StringUtil.notEmpty(accessToken.token) && !this.isTokenExpired(accessToken.expires);
28
+ return OAuthUtil.isValidToken(this.idToken);
60
29
  }
61
30
 
62
31
  hasValidAccessToken(privilege: string): boolean {
63
- return this.isValidAccessToken(this.accessTokens.get(privilege));
32
+ return OAuthUtil.isValidToken(this.accessTokens.get(privilege));
64
33
  }
65
34
 
66
35
  reset() {
67
36
  this.idToken = undefined;
68
- this.eventManager.triggerEvent('id-token-changed', undefined);
69
37
  this.accessTokens.clear();
70
38
  }
71
39
 
40
+ /**
41
+ * Get stored id token or ask the provider, this will trigger redirect to login screen in case of the default provider
42
+ */
72
43
  getIdTokenInternal(): Promise<IdTokenPayload> {
73
44
  if (this.idToken === undefined || !this.hasValidIdToken()) {
74
45
  return this.freshIdTokenProvider.getIdToken();
@@ -76,11 +47,17 @@ export class OAuthTokenManager implements OAuthIdTokenProvider {
76
47
  return Promise.resolve(this.idToken);
77
48
  }
78
49
 
50
+ /**
51
+ * Get id token, refresh it if needed
52
+ */
79
53
  getIdToken(): Promise<IdTokenPayload> {
80
54
  return this.getIdTokenInternal()
81
55
  .then(
82
56
  (t: IdTokenPayload) => {
83
- if (this.isTokenReadyForRefresh(t.issuedAt, t.expires)) {
57
+ if (!OAuthUtil.isValidToken(t)) {
58
+ return Promise.reject('Received invalid ID token!');
59
+ }
60
+ if (OAuthUtil.isTokenReadyForRefresh(t)) {
84
61
  return this.oAuthServer
85
62
  .refreshIdToken({idToken: t.token})
86
63
  .then(
@@ -101,11 +78,7 @@ export class OAuthTokenManager implements OAuthIdTokenProvider {
101
78
  }
102
79
 
103
80
  setIdToken(token?: IdTokenPayload) {
104
- if (!this.isValidIdToken(token)) {
105
- throw new Error("Received ID token is not valid!");
106
- }
107
81
  this.idToken = token;
108
- this.eventManager.triggerEvent('id-token-changed', token);
109
82
  }
110
83
 
111
84
  verifyIdToken(token: string): Promise<IdTokenPayload> {
@@ -125,7 +98,7 @@ export class OAuthTokenManager implements OAuthIdTokenProvider {
125
98
  (idToken: string) => this.oAuthServer
126
99
  .requestAccessToken({idToken: idToken, targetAudience: this.audience, privilege: privilege})
127
100
  .then((act: AccessTokenPayload) => {
128
- if (!this.isValidAccessToken(act)) {
101
+ if (!OAuthUtil.isValidToken(act)) {
129
102
  return Promise.reject("Received access token is not valid!");
130
103
  }
131
104
  this.accessTokens.set(privilege, act);
@@ -136,9 +109,9 @@ export class OAuthTokenManager implements OAuthIdTokenProvider {
136
109
 
137
110
  getAccessToken(privilege: string): Promise<string> {
138
111
  const existing = this.accessTokens.get(privilege);
139
- if (existing === undefined || !this.isValidAccessToken(existing)) return this.getAccessTokenInternal(privilege).then((t) => t.token);
112
+ if (existing === undefined || !OAuthUtil.isValidToken(existing)) return this.getAccessTokenInternal(privilege).then((t) => t.token);
140
113
  // preload access token if it is going to expire soon
141
- if (this.isTokenReadyForRefresh(existing.issuedAt, existing.expires)) this.getAccessTokenInternal(privilege);
114
+ if (OAuthUtil.isTokenReadyForRefresh(existing)) this.getAccessTokenInternal(privilege);
142
115
  return Promise.resolve(existing.token);
143
116
  }
144
117
 
@@ -1,6 +1,6 @@
1
1
  import {OAuthTokenManager} from "./OAuthTokenManager";
2
2
  import {RestClient} from "../client";
3
- import {IdTokenPayload} from "./OAuthRestClient";
3
+ import {IdTokenPayload, TokenResponsePayloadBase} from "./OAuthRestClient";
4
4
  import {LazyAsync} from "../cache";
5
5
  import {OAuthIdTokenProvider} from "./tokenprovider/OAuthIdTokenProvider";
6
6
  import {IdTokenProviderDefault} from "./tokenprovider/IdTokenProviderDefault";
@@ -12,7 +12,7 @@ export type ServerOAuthInfoPayload = {
12
12
  version: string;
13
13
  }
14
14
 
15
- export class RestClientWithOAuth extends RestClient {
15
+ export class RestClientWithOAuth extends RestClient implements OAuthIdTokenProvider {
16
16
 
17
17
  private insecureClient: RestClient;
18
18
 
@@ -37,11 +37,15 @@ export class RestClientWithOAuth extends RestClient {
37
37
  this.tokenManager = new LazyAsync<OAuthTokenManager>(() => this.getTokenManagerInternal());
38
38
  }
39
39
 
40
+ getIdToken(): Promise<IdTokenPayload> {
41
+ return this.getTokenManager().then(t => t.getIdToken());
42
+ }
43
+
40
44
  /**
41
- * Attempt to get ID token from the provider, this will trigger redirect to login screen in case of the default provider
45
+ * Attempt to get ID token from token manager
42
46
  */
43
47
  initialize(): Promise<any> {
44
- return this.getTokenManager().then(tm => tm.getIdToken())
48
+ return this.getIdToken();
45
49
  }
46
50
 
47
51
  logout(): Promise<any> {
@@ -2,7 +2,7 @@ import {OAuthIdTokenProvider} from "./OAuthIdTokenProvider";
2
2
  import {IdTokenPayload} from "../OAuthRestClient";
3
3
  import {IdTokenProviderLogin} from "./IdTokenProviderLogin";
4
4
  import {RestClientWithOAuth} from "../RestClientWithOAuth";
5
- import { IdTokenProviderUrl } from "./IdTokenProviderUrl";
5
+ import {IdTokenProviderUrl} from "./IdTokenProviderUrl";
6
6
  import {IdTokenProviderStorage} from "./IdTokenProviderStorage";
7
7
 
8
8
  export class IdTokenProviderDefault implements OAuthIdTokenProvider {
@@ -35,10 +35,12 @@ export class IdTokenProviderDefault implements OAuthIdTokenProvider {
35
35
  );
36
36
  }
37
37
  )
38
- .then((t) => {
39
- this.storage.saveIdTokenToLocalStorage(t);
40
- return t;
41
- });
38
+ .then(
39
+ (t) => {
40
+ this.storage.saveIdTokenToLocalStorage(t);
41
+ return t;
42
+ }
43
+ );
42
44
  }
43
45
 
44
46
  }
@@ -1,13 +1,14 @@
1
1
  import {OAuthIdTokenProvider} from "./OAuthIdTokenProvider";
2
2
  import {IdTokenPayload} from "../OAuthRestClient";
3
3
  import {JsonUtil} from "../../util";
4
+ import {OAuthUtil} from "../../util/OAuthUtil";
4
5
 
5
6
  export class IdTokenProviderStorage implements OAuthIdTokenProvider {
6
7
 
7
8
  key: string;
8
9
 
9
10
  constructor(storageKey?: string) {
10
- this.key = storageKey || 'id-token';
11
+ this.key = storageKey || '';
11
12
  }
12
13
 
13
14
  saveIdTokenToLocalStorage(token: IdTokenPayload | null) {
@@ -25,8 +26,8 @@ export class IdTokenProviderStorage implements OAuthIdTokenProvider {
25
26
 
26
27
  getIdToken(): Promise<IdTokenPayload> {
27
28
  const token = this.getIdTokenFromLocalStorage();
28
- if (token) return Promise.resolve(token);
29
- return Promise.reject("No token found in storage!");
29
+ if (token && OAuthUtil.isValidToken(token)) return Promise.resolve(token);
30
+ return Promise.reject("No valid token found in storage!");
30
31
  }
31
32
 
32
33
  }
@@ -0,0 +1,24 @@
1
+ import {TokenResponsePayloadBase} from "../oauth";
2
+ import {StringUtil} from "./StringUtil";
3
+
4
+ export class OAuthUtil {
5
+
6
+ static isValidToken(token?: TokenResponsePayloadBase | null): boolean {
7
+ return token !== undefined && token !== null && StringUtil.notEmpty(token.token) && !OAuthUtil.isTokenExpired(token);
8
+ }
9
+
10
+ static isTokenExpired(token?: TokenResponsePayloadBase | null): boolean {
11
+ if (token === undefined || token === null) return false;
12
+ if (token.expires === undefined || token.expires === null) return false;
13
+ return (token.expires < new Date());
14
+ }
15
+
16
+ static isTokenReadyForRefresh(token?: TokenResponsePayloadBase | null): boolean {
17
+ if (token === undefined || token === null) return false;
18
+ if (OAuthUtil.isTokenExpired(token)) return false;
19
+ if (token.expires === undefined || token.expires === null) return false;
20
+ const middle = new Date((token.expires.getTime() + token.issuedAt.getTime()) / 2);
21
+ const now = new Date();
22
+ return (middle < now);
23
+ }
24
+ }