@dehwyyy/auth 1.0.2 → 1.0.4
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/client/client.d.ts +1 -1
- package/dist/client/client.js +2 -2
- package/dist/client/middleware.d.ts +3 -1
- package/dist/client/middleware.js +9 -4
- package/dist/guard/index.d.ts +9 -12
- package/dist/guard/index.js +28 -25
- package/dist/index.d.ts +12 -8
- package/dist/index.js +71 -17
- package/dist/types.d.ts +16 -0
- package/dist/types.js +2 -0
- package/package.json +1 -1
package/dist/client/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { paths } from './schema';
|
|
2
|
-
export declare const getClient: (app: string, baseUrl: string) => import("openapi-fetch").Client<paths, `${string}/${string}`>;
|
|
2
|
+
export declare const getClient: (app: string, baseUrl: string, redirectBaseUrl: string, redirectUriPrefix?: string) => import("openapi-fetch").Client<paths, `${string}/${string}`>;
|
package/dist/client/client.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import createClient from 'openapi-fetch';
|
|
2
2
|
import { Middleware } from './middleware';
|
|
3
3
|
let client = null;
|
|
4
|
-
export const getClient = (app, baseUrl) => {
|
|
4
|
+
export const getClient = (app, baseUrl, redirectBaseUrl, redirectUriPrefix = "") => {
|
|
5
5
|
if (!client) {
|
|
6
6
|
client = createClient({
|
|
7
7
|
baseUrl,
|
|
8
8
|
credentials: 'include',
|
|
9
9
|
});
|
|
10
|
-
const middleware = new Middleware(app, baseUrl);
|
|
10
|
+
const middleware = new Middleware(app, baseUrl, redirectBaseUrl, redirectUriPrefix);
|
|
11
11
|
client.use(middleware.AuthorizationHeaderAttacher, middleware.TokenRefresher);
|
|
12
12
|
}
|
|
13
13
|
return client;
|
|
@@ -2,7 +2,9 @@ import type { Middleware as OpenAPIMiddleware } from 'openapi-fetch';
|
|
|
2
2
|
export declare class Middleware {
|
|
3
3
|
private app;
|
|
4
4
|
private baseUrl;
|
|
5
|
-
|
|
5
|
+
private redirectBaseUrl;
|
|
6
|
+
private redirectUriPrefix;
|
|
7
|
+
constructor(app: string, baseUrl: string, redirectBaseUrl: string, redirectUriPrefix?: string);
|
|
6
8
|
get AuthorizationHeaderAttacher(): OpenAPIMiddleware;
|
|
7
9
|
get TokenRefresher(): OpenAPIMiddleware;
|
|
8
10
|
}
|
|
@@ -2,15 +2,19 @@ import { GetAuthService } from '../index';
|
|
|
2
2
|
export class Middleware {
|
|
3
3
|
app;
|
|
4
4
|
baseUrl;
|
|
5
|
-
|
|
5
|
+
redirectBaseUrl;
|
|
6
|
+
redirectUriPrefix;
|
|
7
|
+
constructor(app, baseUrl, redirectBaseUrl, redirectUriPrefix = "") {
|
|
6
8
|
this.app = app;
|
|
7
9
|
this.baseUrl = baseUrl;
|
|
10
|
+
this.redirectBaseUrl = redirectBaseUrl;
|
|
11
|
+
this.redirectUriPrefix = redirectUriPrefix;
|
|
8
12
|
}
|
|
9
13
|
get AuthorizationHeaderAttacher() {
|
|
10
|
-
const
|
|
14
|
+
const auth = GetAuthService(this.app, this.baseUrl, this.redirectBaseUrl, this.redirectUriPrefix);
|
|
11
15
|
return {
|
|
12
16
|
async onRequest({ request }) {
|
|
13
|
-
return
|
|
17
|
+
return auth.WithAuthorizationToken(request);
|
|
14
18
|
},
|
|
15
19
|
};
|
|
16
20
|
}
|
|
@@ -21,7 +25,8 @@ export class Middleware {
|
|
|
21
25
|
if (response.status !== 401 || request.url.includes('/auth/refresh')) {
|
|
22
26
|
return response;
|
|
23
27
|
}
|
|
24
|
-
|
|
28
|
+
const auth = GetAuthService(t.app, t.baseUrl, t.redirectBaseUrl, t.redirectUriPrefix);
|
|
29
|
+
return auth.RefreshAndRetry(request, response);
|
|
25
30
|
},
|
|
26
31
|
};
|
|
27
32
|
}
|
package/dist/guard/index.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
constructor(app: string, apiURL: string, redirectBaseUrl: string, redirectUriPrefix?: string);
|
|
11
|
-
private getLoginRedirectPath;
|
|
1
|
+
import { GetAuthService } from '../index';
|
|
2
|
+
import { Route } from '../types';
|
|
3
|
+
export declare class Guard {
|
|
4
|
+
private getAuthService;
|
|
5
|
+
private onUserRetrieve?;
|
|
6
|
+
constructor(getAuthService: () => ReturnType<typeof GetAuthService>, onUserRetrieve?: ((user: {
|
|
7
|
+
userId: string;
|
|
8
|
+
roles: string[];
|
|
9
|
+
}) => void) | undefined);
|
|
12
10
|
Auth: (roles?: string[]) => (to: Route, from: Route) => Promise<string | true>;
|
|
13
11
|
}
|
|
14
|
-
export {};
|
package/dist/guard/index.js
CHANGED
|
@@ -1,57 +1,60 @@
|
|
|
1
1
|
import { Storage, StorageKey } from '../client/storage/localStorage';
|
|
2
|
-
import { GetAuthService } from '../index';
|
|
3
2
|
let meCache = null;
|
|
4
3
|
const ME_CACHE_TTL_MS = 15 * 1000;
|
|
5
4
|
function arrayIntercept(arr1, arr2) {
|
|
6
5
|
return arr1.filter((item) => arr2.includes(item));
|
|
7
6
|
}
|
|
8
|
-
export class
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this.app = app;
|
|
15
|
-
this.apiURL = apiURL;
|
|
16
|
-
this.redirectBaseUrl = redirectBaseUrl;
|
|
17
|
-
this.redirectUriPrefix = redirectUriPrefix;
|
|
18
|
-
}
|
|
19
|
-
getLoginRedirectPath(to, from) {
|
|
20
|
-
const redirectUri = from.query['redirect_uri'] || encodeURIComponent(to.fullPath);
|
|
21
|
-
const redirectPath = `${this.redirectBaseUrl}?redirect_uri=${this.redirectUriPrefix}${redirectUri}`;
|
|
22
|
-
return redirectPath;
|
|
7
|
+
export class Guard {
|
|
8
|
+
getAuthService;
|
|
9
|
+
onUserRetrieve;
|
|
10
|
+
constructor(getAuthService, onUserRetrieve) {
|
|
11
|
+
this.getAuthService = getAuthService;
|
|
12
|
+
this.onUserRetrieve = onUserRetrieve;
|
|
23
13
|
}
|
|
24
14
|
Auth = (roles = []) => {
|
|
25
15
|
return async (to, from) => {
|
|
26
|
-
const
|
|
27
|
-
const
|
|
16
|
+
const auth = this.getAuthService();
|
|
17
|
+
const loginRedirect = auth.GetLoginRedirectPath(to, from);
|
|
18
|
+
let token = Storage.Get(StorageKey.ACCESS_TOKEN);
|
|
28
19
|
if (!token) {
|
|
29
20
|
if (roles.length === 0)
|
|
30
21
|
return true;
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
// try to refresh
|
|
23
|
+
token = await auth.Refresh();
|
|
24
|
+
if (token) {
|
|
25
|
+
Storage.Set(StorageKey.ACCESS_TOKEN, token);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return loginRedirect.redirect();
|
|
29
|
+
}
|
|
33
30
|
}
|
|
34
31
|
const now = Date.now();
|
|
35
32
|
if (meCache && meCache.expiresAt > now) {
|
|
36
33
|
const data = meCache.data;
|
|
37
34
|
if (arrayIntercept(data.roles, roles).length === 0) {
|
|
38
|
-
return loginRedirect;
|
|
35
|
+
return loginRedirect.redirect();
|
|
39
36
|
}
|
|
40
37
|
return true;
|
|
41
38
|
}
|
|
42
|
-
const response = await
|
|
39
|
+
const response = await auth.GetMe();
|
|
43
40
|
if (!response) {
|
|
44
41
|
console.warn('Access denied');
|
|
45
|
-
return loginRedirect;
|
|
42
|
+
return loginRedirect.redirect();
|
|
46
43
|
}
|
|
47
44
|
meCache = { data: response, expiresAt: Date.now() + ME_CACHE_TTL_MS };
|
|
45
|
+
if (this.onUserRetrieve) {
|
|
46
|
+
this.onUserRetrieve({
|
|
47
|
+
userId: response.userId,
|
|
48
|
+
roles: response.roles,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
48
51
|
if (response.roles.length === 0) {
|
|
49
52
|
console.warn('No roles found');
|
|
50
|
-
return loginRedirect;
|
|
53
|
+
return loginRedirect.redirect();
|
|
51
54
|
}
|
|
52
55
|
if (arrayIntercept(response.roles, roles).length === 0) {
|
|
53
56
|
console.warn('Access denied');
|
|
54
|
-
return loginRedirect;
|
|
57
|
+
return loginRedirect.redirect();
|
|
55
58
|
}
|
|
56
59
|
return true;
|
|
57
60
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
userId: string;
|
|
3
|
-
roles: string[];
|
|
4
|
-
}
|
|
1
|
+
import { GetMeResponse, Route } from './types';
|
|
5
2
|
declare class AuthService {
|
|
6
3
|
private app;
|
|
7
4
|
private apiURL;
|
|
5
|
+
private redirectBaseUrl;
|
|
6
|
+
private redirectUriPrefix;
|
|
8
7
|
private refreshPromise;
|
|
9
|
-
constructor(app: string, apiURL: string);
|
|
10
|
-
withApp(app: string): this;
|
|
8
|
+
constructor(app: string, apiURL: string, redirectBaseUrl: string, redirectUriPrefix?: string);
|
|
11
9
|
private getClient;
|
|
12
10
|
/**
|
|
13
11
|
* @description Refresh access token
|
|
14
12
|
* @returns `accessToken` -> refresh ok. `null` -> refresh failed
|
|
15
13
|
**/
|
|
16
14
|
private doRefresh;
|
|
17
|
-
|
|
15
|
+
withApp(app: string): this;
|
|
18
16
|
WithAuthorizationToken(request: Request, token?: string | null): Request;
|
|
17
|
+
GetLoginRedirectPath(to: Route, from?: Route): {
|
|
18
|
+
redirect: () => string;
|
|
19
|
+
};
|
|
20
|
+
GetMe(verbose?: boolean): Promise<GetMeResponse | null>;
|
|
21
|
+
Logout(): Promise<boolean>;
|
|
22
|
+
Refresh(): Promise<string | null>;
|
|
19
23
|
RefreshAndRetry(request: Request, response: Response): Promise<Response>;
|
|
20
24
|
}
|
|
21
|
-
export declare function GetAuthService(app: string, apiURL: string): AuthService;
|
|
25
|
+
export declare function GetAuthService(app: string, apiURL: string, redirectBaseUrl: string, redirectUriPrefix: string): AuthService;
|
|
22
26
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -3,18 +3,18 @@ import { Storage, StorageKey } from './client/storage/localStorage';
|
|
|
3
3
|
class AuthService {
|
|
4
4
|
app;
|
|
5
5
|
apiURL;
|
|
6
|
+
redirectBaseUrl;
|
|
7
|
+
redirectUriPrefix;
|
|
6
8
|
// теперь обещание возвращает сам новый токен или null
|
|
7
9
|
refreshPromise = null;
|
|
8
|
-
constructor(app, apiURL) {
|
|
10
|
+
constructor(app, apiURL, redirectBaseUrl, redirectUriPrefix = "") {
|
|
9
11
|
this.app = app;
|
|
10
12
|
this.apiURL = apiURL;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.app = app;
|
|
14
|
-
return this;
|
|
13
|
+
this.redirectBaseUrl = redirectBaseUrl;
|
|
14
|
+
this.redirectUriPrefix = redirectUriPrefix;
|
|
15
15
|
}
|
|
16
16
|
getClient() {
|
|
17
|
-
return getClient(this.app, this.apiURL);
|
|
17
|
+
return getClient(this.app, this.apiURL, this.redirectBaseUrl, this.redirectUriPrefix);
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* @description Refresh access token
|
|
@@ -34,16 +34,43 @@ class AuthService {
|
|
|
34
34
|
Storage.Delete(StorageKey.ACCESS_TOKEN);
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
withApp(app) {
|
|
38
|
+
this.app = app;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
WithAuthorizationToken(request, token = null) {
|
|
42
|
+
token ??= Storage.Get(StorageKey.ACCESS_TOKEN);
|
|
43
|
+
if (token) {
|
|
44
|
+
request.headers.set('Authorization', `Bearer ${token}`);
|
|
45
|
+
}
|
|
46
|
+
return request;
|
|
47
|
+
}
|
|
48
|
+
GetLoginRedirectPath(to, from) {
|
|
49
|
+
const redirectUri = from?.query['redirect_uri'] || encodeURIComponent(to.fullPath);
|
|
50
|
+
const redirectPath = `${this.redirectBaseUrl}?redirect_uri=${this.redirectUriPrefix}${redirectUri}`;
|
|
51
|
+
return {
|
|
52
|
+
redirect: () => {
|
|
53
|
+
if (redirectPath.startsWith('http')) {
|
|
54
|
+
window.location.href = redirectPath;
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
return redirectPath;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async GetMe(verbose = false) {
|
|
62
|
+
let token = Storage.Get(StorageKey.ACCESS_TOKEN);
|
|
40
63
|
if (!token) {
|
|
41
|
-
|
|
64
|
+
token = await this.Refresh();
|
|
65
|
+
if (!token) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
42
68
|
}
|
|
43
69
|
const { response, data, error } = await this.getClient().GET('/auth/me', {
|
|
44
70
|
params: {
|
|
45
71
|
query: {
|
|
46
72
|
app: this.app,
|
|
73
|
+
verbose: verbose ? 'all' : 'none',
|
|
47
74
|
},
|
|
48
75
|
header: {
|
|
49
76
|
Authorization: `Bearer ${token}`,
|
|
@@ -61,14 +88,41 @@ class AuthService {
|
|
|
61
88
|
return {
|
|
62
89
|
userId: data.user_id,
|
|
63
90
|
roles: data.roles || [],
|
|
91
|
+
active: data.active || false,
|
|
92
|
+
info: !data.info ? undefined : {
|
|
93
|
+
verified: data.info.verified || false,
|
|
94
|
+
username: data.info.username,
|
|
95
|
+
email: data.info.email,
|
|
96
|
+
avatar: data.info.avatar,
|
|
97
|
+
data: data.info.data,
|
|
98
|
+
},
|
|
64
99
|
};
|
|
65
100
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
101
|
+
async Logout() {
|
|
102
|
+
Storage.Delete(StorageKey.ACCESS_TOKEN);
|
|
103
|
+
const { response, error } = await this.getClient().POST('/auth/logout');
|
|
104
|
+
if (error || !response.ok) {
|
|
105
|
+
console.error(error, response);
|
|
106
|
+
return false;
|
|
70
107
|
}
|
|
71
|
-
return
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
async Refresh() {
|
|
111
|
+
if (this.refreshPromise) {
|
|
112
|
+
return this.refreshPromise;
|
|
113
|
+
}
|
|
114
|
+
this.refreshPromise = this.doRefresh();
|
|
115
|
+
let token = null;
|
|
116
|
+
try {
|
|
117
|
+
token = await this.refreshPromise;
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
console.error(e);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
this.refreshPromise = null;
|
|
124
|
+
}
|
|
125
|
+
return token;
|
|
72
126
|
}
|
|
73
127
|
async RefreshAndRetry(request, response) {
|
|
74
128
|
if (!this.refreshPromise) {
|
|
@@ -98,9 +152,9 @@ class AuthService {
|
|
|
98
152
|
}
|
|
99
153
|
}
|
|
100
154
|
let auth = null;
|
|
101
|
-
export function GetAuthService(app, apiURL) {
|
|
155
|
+
export function GetAuthService(app, apiURL, redirectBaseUrl, redirectUriPrefix) {
|
|
102
156
|
if (!auth) {
|
|
103
|
-
auth = new AuthService(app, apiURL);
|
|
157
|
+
auth = new AuthService(app, apiURL, redirectBaseUrl, redirectUriPrefix);
|
|
104
158
|
}
|
|
105
159
|
return auth.withApp(app);
|
|
106
160
|
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface GetMeResponse {
|
|
2
|
+
roles: string[];
|
|
3
|
+
userId: string;
|
|
4
|
+
active: boolean;
|
|
5
|
+
info?: {
|
|
6
|
+
verified: boolean;
|
|
7
|
+
avatar?: string;
|
|
8
|
+
data?: Record<string, unknown>;
|
|
9
|
+
email?: string;
|
|
10
|
+
username?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface Route {
|
|
14
|
+
query: Record<string, unknown>;
|
|
15
|
+
fullPath: string;
|
|
16
|
+
}
|
package/dist/types.js
ADDED