zavadil-ts-common 1.1.39 → 1.1.41
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/component/OAuthRestClient.d.ts +4 -18
- package/dist/component/OAuthTokenManager.d.ts +21 -0
- package/dist/component/RestClientWithOAuth.d.ts +18 -0
- package/dist/component/index.d.ts +1 -1
- package/dist/index.d.ts +11 -27
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cache/index.ts +5 -0
- package/src/client/EntityCachedClient.ts +30 -0
- package/src/client/EntityClient.ts +35 -0
- package/src/client/EntityClientWithStub.ts +26 -0
- package/src/client/LookupClient.ts +45 -0
- package/src/client/index.ts +6 -0
- package/src/component/index.ts +1 -8
- package/src/index.ts +5 -2
- package/src/{component → oauth}/OAuthRestClient.ts +6 -27
- package/src/oauth/OAuthTokenManager.ts +110 -0
- package/src/oauth/RestClientWithOAuth.ts +61 -0
- package/src/oauth/index.ts +6 -0
- package/src/component/OAuthSessionManager.ts +0 -143
- /package/src/{component → cache}/CacheAsync.ts +0 -0
- /package/src/{component → cache}/HashCacheAsync.ts +0 -0
- /package/src/{component → cache}/Lazy.ts +0 -0
- /package/src/{component → cache}/LazyAsync.ts +0 -0
- /package/src/{component → client}/RestClient.ts +0 -0
- /package/src/{component → oauth}/OAuthSubject.ts +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
import {RestClient} from "
|
1
|
+
import {RestClient} from "../client/RestClient";
|
2
2
|
import {StringUtil} from "../util";
|
3
3
|
|
4
4
|
export type TokenRequestPayloadBase = {
|
@@ -9,8 +9,8 @@ export type RequestAccessTokenPayload = TokenRequestPayloadBase & {
|
|
9
9
|
idToken: string;
|
10
10
|
}
|
11
11
|
|
12
|
-
export type
|
13
|
-
|
12
|
+
export type RequestIdTokenFromPrevTokenPayload = {
|
13
|
+
idToken: string;
|
14
14
|
}
|
15
15
|
|
16
16
|
export type RequestIdTokenFromLoginPayload = TokenRequestPayloadBase & {
|
@@ -18,12 +18,8 @@ export type RequestIdTokenFromLoginPayload = TokenRequestPayloadBase & {
|
|
18
18
|
password: string;
|
19
19
|
}
|
20
20
|
|
21
|
-
export type RefreshAccessTokenPayload = TokenRequestPayloadBase & {
|
22
|
-
accessToken: string;
|
23
|
-
refreshToken: string;
|
24
|
-
}
|
25
|
-
|
26
21
|
export type TokenResponsePayloadBase = {
|
22
|
+
issuedAt: Date;
|
27
23
|
expires?: Date | null;
|
28
24
|
}
|
29
25
|
|
@@ -47,16 +43,6 @@ export type JwksPayload = {
|
|
47
43
|
keys: Array<JwKeyPayload>;
|
48
44
|
}
|
49
45
|
|
50
|
-
export type SessionPayload = {
|
51
|
-
session_id: string;
|
52
|
-
plugin_id: number;
|
53
|
-
user_id: number;
|
54
|
-
account_id: number;
|
55
|
-
server: string;
|
56
|
-
user_name: string;
|
57
|
-
timezone: string;
|
58
|
-
}
|
59
|
-
|
60
46
|
/**
|
61
47
|
* This implements rest client for OAuth server - https://github.com/lotcz/oauth-server
|
62
48
|
*/
|
@@ -74,19 +60,12 @@ export class OAuthRestClient extends RestClient {
|
|
74
60
|
return this.postJson('id-tokens/from-login', request);
|
75
61
|
}
|
76
62
|
|
77
|
-
|
78
|
-
return this.postJson('id-tokens/
|
63
|
+
refreshIdToken(request: RequestIdTokenFromPrevTokenPayload): Promise<IdTokenPayload> {
|
64
|
+
return this.postJson('id-tokens/refresh', request);
|
79
65
|
}
|
80
66
|
|
81
67
|
requestAccessToken(request: RequestAccessTokenPayload): Promise<AccessTokenPayload> {
|
82
68
|
return this.postJson('access-tokens/from-id-token', request);
|
83
69
|
}
|
84
70
|
|
85
|
-
refreshAccessToken(request: RefreshAccessTokenPayload): Promise<AccessTokenPayload> {
|
86
|
-
return this.postJson('access-tokens/refresh', request);
|
87
|
-
}
|
88
|
-
|
89
|
-
loadSessionById(sessionId: string): Promise<SessionPayload> {
|
90
|
-
return this.getJson(`sessions/${sessionId}`);
|
91
|
-
}
|
92
71
|
}
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import {AccessTokenPayload, IdTokenPayload, OAuthRestClient} from "./OAuthRestClient";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Manages refresh of id and access tokens.
|
5
|
+
*/
|
6
|
+
export class OAuthTokenManager {
|
7
|
+
|
8
|
+
oAuthServer: OAuthRestClient;
|
9
|
+
|
10
|
+
audience: string;
|
11
|
+
|
12
|
+
idToken?: IdTokenPayload;
|
13
|
+
|
14
|
+
accessToken?: AccessTokenPayload;
|
15
|
+
|
16
|
+
constructor(oAuthServerBaseUrl: string, targetAudience: string) {
|
17
|
+
this.audience = targetAudience;
|
18
|
+
this.oAuthServer = new OAuthRestClient(oAuthServerBaseUrl);
|
19
|
+
}
|
20
|
+
|
21
|
+
isTokenExpired(expires?: Date | null): boolean {
|
22
|
+
if (expires === undefined || expires === null) return false;
|
23
|
+
const now = Date.now();
|
24
|
+
const exp = new Date(expires).getTime();
|
25
|
+
return (exp < now);
|
26
|
+
}
|
27
|
+
|
28
|
+
isTokenReadyForRefresh(issuedAt: Date, expires?: Date | null): boolean {
|
29
|
+
if (expires === undefined || expires === null) return false;
|
30
|
+
const middle = new Date((expires.getTime() + issuedAt.getTime()) / 2);
|
31
|
+
const now = new Date();
|
32
|
+
return (middle < now);
|
33
|
+
}
|
34
|
+
|
35
|
+
isValidIdToken(idToken?: IdTokenPayload): boolean {
|
36
|
+
return idToken !== undefined && !this.isTokenExpired(idToken.expires);
|
37
|
+
}
|
38
|
+
|
39
|
+
hasValidIdToken(): boolean {
|
40
|
+
return this.isValidIdToken(this.idToken);
|
41
|
+
}
|
42
|
+
|
43
|
+
isValidAccessToken(accessToken?: AccessTokenPayload): boolean {
|
44
|
+
return accessToken !== undefined && !this.isTokenExpired(accessToken.expires);
|
45
|
+
}
|
46
|
+
|
47
|
+
hasValidAccessToken(): boolean {
|
48
|
+
return this.isValidAccessToken(this.accessToken);
|
49
|
+
}
|
50
|
+
|
51
|
+
reset() {
|
52
|
+
this.idToken = undefined;
|
53
|
+
this.accessToken = undefined;
|
54
|
+
}
|
55
|
+
|
56
|
+
getIdToken(): Promise<string> {
|
57
|
+
if (this.idToken === undefined || !this.hasValidIdToken()) {
|
58
|
+
return Promise.reject("No valid ID token!");
|
59
|
+
}
|
60
|
+
if (this.isTokenReadyForRefresh(this.idToken.issuedAt, this.idToken.expires)) {
|
61
|
+
return this.oAuthServer
|
62
|
+
.refreshIdToken({idToken: this.idToken.idToken})
|
63
|
+
.then(
|
64
|
+
(t) => {
|
65
|
+
if (!this.isValidIdToken(t)) {
|
66
|
+
return Promise.reject("Received ID token is not valid!");
|
67
|
+
}
|
68
|
+
this.idToken = t;
|
69
|
+
return t.idToken;
|
70
|
+
}
|
71
|
+
)
|
72
|
+
}
|
73
|
+
return Promise.resolve(this.idToken.idToken);
|
74
|
+
}
|
75
|
+
|
76
|
+
login(login: string, password: string): Promise<boolean> {
|
77
|
+
this.reset();
|
78
|
+
return this.oAuthServer.requestIdTokenFromLogin({login: login, password: password, targetAudience: this.audience})
|
79
|
+
.then(
|
80
|
+
(t) => {
|
81
|
+
if (!this.isValidIdToken(t)) {
|
82
|
+
return Promise.reject("Received ID token is not valid!");
|
83
|
+
}
|
84
|
+
this.idToken = t;
|
85
|
+
return true;
|
86
|
+
})
|
87
|
+
.catch((e) => false);
|
88
|
+
}
|
89
|
+
|
90
|
+
getAccessToken(): Promise<string> {
|
91
|
+
if (this.hasValidAccessToken()) {
|
92
|
+
return Promise.resolve(String(this.accessToken?.accessToken));
|
93
|
+
} else {
|
94
|
+
return this.getIdToken()
|
95
|
+
.then(
|
96
|
+
(idToken: string) => this.oAuthServer
|
97
|
+
.requestAccessToken({idToken: idToken, targetAudience: this.audience})
|
98
|
+
.then((act: AccessTokenPayload) => {
|
99
|
+
if (!this.isValidAccessToken(act)) {
|
100
|
+
return Promise.reject("Received access token is not valid!");
|
101
|
+
}
|
102
|
+
this.accessToken = act;
|
103
|
+
return act.accessToken;
|
104
|
+
})
|
105
|
+
);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
}
|
110
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import {OAuthTokenManager} from "./OAuthTokenManager";
|
2
|
+
import { RestClient, RestClientHeaders } from "../client/RestClient";
|
3
|
+
|
4
|
+
export type ServerOAuthInfoPayload = {
|
5
|
+
debugMode?: boolean;
|
6
|
+
targetAudience: string;
|
7
|
+
oauthServerUrl: string;
|
8
|
+
version: string;
|
9
|
+
}
|
10
|
+
|
11
|
+
export class RestClientWithOAuth extends RestClient {
|
12
|
+
|
13
|
+
private tokenManager?: OAuthTokenManager;
|
14
|
+
|
15
|
+
private serverInfo?: ServerOAuthInfoPayload;
|
16
|
+
|
17
|
+
private insecureClient: RestClient;
|
18
|
+
|
19
|
+
constructor(url: string) {
|
20
|
+
super(url);
|
21
|
+
// rest client without OAuth headers
|
22
|
+
this.insecureClient = new RestClient(url);
|
23
|
+
}
|
24
|
+
|
25
|
+
getServerInfo(): Promise<ServerOAuthInfoPayload> {
|
26
|
+
if (this.serverInfo !== undefined) {
|
27
|
+
return Promise.resolve(this.serverInfo);
|
28
|
+
}
|
29
|
+
return this.insecureClient.getJson('status/info')
|
30
|
+
.then((si: ServerOAuthInfoPayload) => {
|
31
|
+
this.serverInfo = si;
|
32
|
+
return this.serverInfo;
|
33
|
+
});
|
34
|
+
}
|
35
|
+
|
36
|
+
getTokenManager(): Promise<OAuthTokenManager> {
|
37
|
+
if (this.tokenManager !== undefined) {
|
38
|
+
return Promise.resolve(this.tokenManager);
|
39
|
+
}
|
40
|
+
return this.getServerInfo()
|
41
|
+
.then((info) => new OAuthTokenManager(info.oauthServerUrl, info.targetAudience));
|
42
|
+
}
|
43
|
+
|
44
|
+
login(login: string, password: string): Promise<boolean> {
|
45
|
+
return this.getTokenManager().then((m) => m.login(login, password));
|
46
|
+
}
|
47
|
+
|
48
|
+
getHeaders(): Promise<RestClientHeaders> {
|
49
|
+
return this.getTokenManager()
|
50
|
+
.then(sm => sm.getAccessToken())
|
51
|
+
.then(
|
52
|
+
(accessToken) => {
|
53
|
+
return {
|
54
|
+
'Content-Type': 'application/json',
|
55
|
+
'Authorization': `Bearer ${accessToken}`
|
56
|
+
}
|
57
|
+
}
|
58
|
+
);
|
59
|
+
}
|
60
|
+
|
61
|
+
}
|
@@ -1,143 +0,0 @@
|
|
1
|
-
import {AccessTokenPayload, IdTokenPayload, OAuthRestClient, SessionPayload} from "./OAuthRestClient";
|
2
|
-
|
3
|
-
export class OAuthSessionManager {
|
4
|
-
|
5
|
-
oAuthServer: OAuthRestClient;
|
6
|
-
|
7
|
-
audience: string;
|
8
|
-
|
9
|
-
idToken?: IdTokenPayload;
|
10
|
-
|
11
|
-
accessToken?: AccessTokenPayload;
|
12
|
-
|
13
|
-
sessionId?: string;
|
14
|
-
|
15
|
-
session?: SessionPayload;
|
16
|
-
|
17
|
-
constructor(oAuthServerBaseUrl: string, targetAudience: string) {
|
18
|
-
this.audience = targetAudience;
|
19
|
-
this.oAuthServer = new OAuthRestClient(oAuthServerBaseUrl);
|
20
|
-
setInterval(() => this.checkAccessTokenRefresh(), 5000);
|
21
|
-
}
|
22
|
-
|
23
|
-
isTokenExpired(expires?: Date | null): boolean {
|
24
|
-
if (expires === undefined || expires === null) return false;
|
25
|
-
const now = Date.now();
|
26
|
-
const exp = new Date(expires).getTime();
|
27
|
-
return (exp < now);
|
28
|
-
}
|
29
|
-
|
30
|
-
isTokenReadyForRefresh(expires?: Date | null): boolean {
|
31
|
-
if (expires === undefined || expires === null) return false;
|
32
|
-
const now = Date.now();
|
33
|
-
const exp = new Date(expires).getTime() - (1000 * 10);
|
34
|
-
return (exp < now);
|
35
|
-
}
|
36
|
-
|
37
|
-
isValidIdToken(idToken?: IdTokenPayload): boolean {
|
38
|
-
return idToken !== undefined && !this.isTokenExpired(idToken.expires);
|
39
|
-
}
|
40
|
-
|
41
|
-
hasValidIdToken(): boolean {
|
42
|
-
return this.isValidIdToken(this.idToken);
|
43
|
-
}
|
44
|
-
|
45
|
-
isValidAccessToken(accessToken?: AccessTokenPayload): boolean {
|
46
|
-
return accessToken !== undefined && !this.isTokenExpired(accessToken.expires);
|
47
|
-
}
|
48
|
-
|
49
|
-
hasValidAccessToken(): boolean {
|
50
|
-
return this.isValidAccessToken(this.accessToken);
|
51
|
-
}
|
52
|
-
|
53
|
-
reset() {
|
54
|
-
this.sessionId = undefined;
|
55
|
-
this.session = undefined;
|
56
|
-
this.idToken = undefined;
|
57
|
-
this.accessToken = undefined;
|
58
|
-
}
|
59
|
-
|
60
|
-
initializeSessionId(sessionId: string) {
|
61
|
-
this.reset();
|
62
|
-
this.sessionId = sessionId;
|
63
|
-
}
|
64
|
-
|
65
|
-
getSession(): Promise<SessionPayload> {
|
66
|
-
if (this.session !== undefined) {
|
67
|
-
return Promise.resolve(this.session);
|
68
|
-
} else {
|
69
|
-
if (this.sessionId === undefined) {
|
70
|
-
return Promise.reject("No session ID!");
|
71
|
-
}
|
72
|
-
return this.oAuthServer
|
73
|
-
.loadSessionById(this.sessionId)
|
74
|
-
.then((session: SessionPayload) => {
|
75
|
-
this.session = session;
|
76
|
-
return this.session;
|
77
|
-
});
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
getIdToken(): Promise<string> {
|
82
|
-
if (this.hasValidIdToken()) {
|
83
|
-
return Promise.resolve(String(this.idToken?.idToken));
|
84
|
-
} else {
|
85
|
-
if (this.sessionId === undefined) {
|
86
|
-
return Promise.reject("No session ID!");
|
87
|
-
}
|
88
|
-
return this.oAuthServer
|
89
|
-
.requestIdTokenFromSession({sessionId: this.sessionId, targetAudience: this.audience})
|
90
|
-
.then((idToken: IdTokenPayload) => {
|
91
|
-
if (!this.isValidIdToken(idToken)) {
|
92
|
-
return Promise.reject("Received ID token is not valid!");
|
93
|
-
}
|
94
|
-
this.idToken = idToken;
|
95
|
-
})
|
96
|
-
.then(() => this.getIdToken());
|
97
|
-
}
|
98
|
-
}
|
99
|
-
|
100
|
-
getAccessToken(): Promise<string> {
|
101
|
-
if (this.hasValidAccessToken()) {
|
102
|
-
return Promise.resolve(String(this.accessToken?.accessToken));
|
103
|
-
} else {
|
104
|
-
return this.getIdToken()
|
105
|
-
.then(
|
106
|
-
(idToken: string) => this.oAuthServer
|
107
|
-
.requestAccessToken({idToken: idToken, targetAudience: this.audience})
|
108
|
-
.then((act: AccessTokenPayload) => {
|
109
|
-
if (!this.isValidAccessToken(act)) {
|
110
|
-
return Promise.reject("Received access token is not valid!");
|
111
|
-
}
|
112
|
-
this.accessToken = act;
|
113
|
-
})
|
114
|
-
)
|
115
|
-
.then(() => this.getAccessToken());
|
116
|
-
}
|
117
|
-
}
|
118
|
-
|
119
|
-
refreshAccessToken() {
|
120
|
-
if (this.accessToken === undefined) throw new Error("No access token to be refreshed!");
|
121
|
-
this.oAuthServer.refreshAccessToken(
|
122
|
-
{
|
123
|
-
targetAudience: this.audience,
|
124
|
-
accessToken: this.accessToken?.accessToken,
|
125
|
-
refreshToken: this.accessToken?.refreshToken
|
126
|
-
}
|
127
|
-
).then(
|
128
|
-
(act: AccessTokenPayload) => {
|
129
|
-
if (!this.isValidAccessToken(act)) {
|
130
|
-
throw new Error("Refreshed access token is not valid!");
|
131
|
-
}
|
132
|
-
this.accessToken = act;
|
133
|
-
}
|
134
|
-
)
|
135
|
-
}
|
136
|
-
|
137
|
-
checkAccessTokenRefresh() {
|
138
|
-
if (this.hasValidAccessToken() && this.isTokenReadyForRefresh(this.accessToken?.expires)) {
|
139
|
-
this.refreshAccessToken();
|
140
|
-
}
|
141
|
-
}
|
142
|
-
}
|
143
|
-
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|