UNPKG

6.89 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.AuthenticationClient = void 0;
4const errors_1 = require("@feathersjs/errors");
5const storage_1 = require("./storage");
6class OauthError extends errors_1.FeathersError {
7 constructor(message, data) {
8 super(message, 'OauthError', 401, 'oauth-error', data);
9 }
10}
11const getMatch = (location, key) => {
12 const regex = new RegExp(`(?:\&?)${key}=([^&]*)`);
13 const match = location.hash ? location.hash.match(regex) : null;
14 if (match !== null) {
15 const [, value] = match;
16 return [value, regex];
17 }
18 return [null, regex];
19};
20class AuthenticationClient {
21 constructor(app, options) {
22 const socket = app.io;
23 const storage = new storage_1.StorageWrapper(app.get('storage') || options.storage);
24 this.app = app;
25 this.options = options;
26 this.authenticated = false;
27 this.app.set('storage', storage);
28 if (socket) {
29 this.handleSocket(socket);
30 }
31 }
32 get service() {
33 return this.app.service(this.options.path);
34 }
35 get storage() {
36 return this.app.get('storage');
37 }
38 handleSocket(socket) {
39 // When the socket disconnects and we are still authenticated, try to reauthenticate right away
40 // the websocket connection will handle timeouts and retries
41 socket.on('disconnect', () => {
42 if (this.authenticated) {
43 this.reAuthenticate(true);
44 }
45 });
46 }
47 /**
48 * Parse the access token or authentication error from the window location hash. Will remove it from the hash
49 * if found.
50 *
51 * @param location The window location
52 * @returns The access token if available, will throw an error if found, otherwise null
53 */
54 getFromLocation(location) {
55 const [accessToken, tokenRegex] = getMatch(location, this.options.locationKey);
56 if (accessToken !== null) {
57 location.hash = location.hash.replace(tokenRegex, '');
58 return Promise.resolve(accessToken);
59 }
60 const [message, errorRegex] = getMatch(location, this.options.locationErrorKey);
61 if (message !== null) {
62 location.hash = location.hash.replace(errorRegex, '');
63 return Promise.reject(new OauthError(decodeURIComponent(message)));
64 }
65 return Promise.resolve(null);
66 }
67 /**
68 * Set the access token in storage.
69 *
70 * @param accessToken The access token to set
71 * @returns
72 */
73 setAccessToken(accessToken) {
74 return this.storage.setItem(this.options.storageKey, accessToken);
75 }
76 /**
77 * Returns the access token from storage or the window location hash.
78 *
79 * @returns The access token from storage or location hash
80 */
81 getAccessToken() {
82 return this.storage.getItem(this.options.storageKey).then((accessToken) => {
83 if (!accessToken && typeof window !== 'undefined' && window.location) {
84 return this.getFromLocation(window.location);
85 }
86 return accessToken || null;
87 });
88 }
89 /**
90 * Remove the access token from storage
91 * @returns The removed access token
92 */
93 removeAccessToken() {
94 return this.storage.removeItem(this.options.storageKey);
95 }
96 /**
97 * Reset the internal authentication state. Usually not necessary to call directly.
98 *
99 * @returns null
100 */
101 reset() {
102 this.app.set('authentication', null);
103 this.authenticated = false;
104 return Promise.resolve(null);
105 }
106 handleError(error, type) {
107 // For NotAuthenticated, PaymentError, Forbidden, NotFound, MethodNotAllowed, NotAcceptable
108 // errors, remove the access token
109 if (error.code > 400 && error.code < 408) {
110 const promise = this.removeAccessToken().then(() => this.reset());
111 return type === 'logout' ? promise : promise.then(() => Promise.reject(error));
112 }
113 return this.reset().then(() => Promise.reject(error));
114 }
115 /**
116 * Try to reauthenticate using the token from storage. Will do nothing if already authenticated unless
117 * `force` is true.
118 *
119 * @param force force reauthentication with the server
120 * @param strategy The name of the strategy to use. Defaults to `options.jwtStrategy`
121 * @param authParams Additional authentication parameters
122 * @returns The reauthentication result
123 */
124 reAuthenticate(force = false, strategy, authParams) {
125 // Either returns the authentication state or
126 // tries to re-authenticate with the stored JWT and strategy
127 let authPromise = this.app.get('authentication');
128 if (!authPromise || force === true) {
129 authPromise = this.getAccessToken().then((accessToken) => {
130 if (!accessToken) {
131 return this.handleError(new errors_1.NotAuthenticated('No accessToken found in storage'), 'authenticate');
132 }
133 return this.authenticate({
134 strategy: strategy || this.options.jwtStrategy,
135 accessToken
136 }, authParams);
137 });
138 this.app.set('authentication', authPromise);
139 }
140 return authPromise;
141 }
142 /**
143 * Authenticate using a specific strategy and data.
144 *
145 * @param authentication The authentication data
146 * @param params Additional parameters
147 * @returns The authentication result
148 */
149 authenticate(authentication, params) {
150 if (!authentication) {
151 return this.reAuthenticate();
152 }
153 const promise = this.service
154 .create(authentication, params)
155 .then((authResult) => {
156 const { accessToken } = authResult;
157 this.authenticated = true;
158 this.app.emit('login', authResult);
159 this.app.emit('authenticated', authResult);
160 return this.setAccessToken(accessToken).then(() => authResult);
161 })
162 .catch((error) => this.handleError(error, 'authenticate'));
163 this.app.set('authentication', promise);
164 return promise;
165 }
166 /**
167 * Log out the current user and remove their token. Will do nothing
168 * if not authenticated.
169 *
170 * @returns The log out result.
171 */
172 logout() {
173 return Promise.resolve(this.app.get('authentication'))
174 .then(() => this.service.remove(null).then((authResult) => this.removeAccessToken()
175 .then(() => this.reset())
176 .then(() => {
177 this.app.emit('logout', authResult);
178 return authResult;
179 })))
180 .catch((error) => this.handleError(error, 'logout'));
181 }
182}
183exports.AuthenticationClient = AuthenticationClient;
184//# sourceMappingURL=core.js.map
\No newline at end of file