@dynamic-labs/sdk-react-core 0.18.28 → 0.18.30

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/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
1
 
2
+ ### [0.18.30](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.29...v0.18.30) (2023-11-27)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * handle origin_check message from authWindow ([#3992](https://github.com/dynamic-labs/DynamicAuth/issues/3992)) ([1f35594](https://github.com/dynamic-labs/DynamicAuth/commit/1f35594fa3b0e10d3e1c6102b82606117a2265e1))
8
+ * null safe check to window object ([#3886](https://github.com/dynamic-labs/DynamicAuth/issues/3886)) ([37b4d36](https://github.com/dynamic-labs/DynamicAuth/commit/37b4d361b61f1045b7a0dc42359eb6cc1ce1b659))
9
+
10
+ ### [0.18.29](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.28...v0.18.29) (2023-11-13)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **bridge:** disconnect mm when locked offsite ([#3872](https://github.com/dynamic-labs/DynamicAuth/issues/3872)) ([4a34492](https://github.com/dynamic-labs/DynamicAuth/commit/4a344926d2987cd31123b9a5ac9c3dbf1efccbe0))
16
+ * only process oauth message coming from the expected origin ([#3805](https://github.com/dynamic-labs/DynamicAuth/issues/3805)) ([970003c](https://github.com/dynamic-labs/DynamicAuth/commit/970003c81cc101dcca2c4a56c48095303377d8ef))
17
+
2
18
  ### [0.18.28](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.27...v0.18.28) (2023-10-30)
3
19
 
4
20
 
package/package.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "0.18.28";
5
+ var version = "0.18.30";
6
6
  var dependencies = {
7
7
  "react-focus-lock": "2.9.2",
8
8
  "@dynamic-labs/iconic": "0.1.32",
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
- var version = "0.18.28";
1
+ var version = "0.18.30";
2
2
  var dependencies = {
3
3
  "react-focus-lock": "2.9.2",
4
4
  "@dynamic-labs/iconic": "0.1.32",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/sdk-react-core",
3
- "version": "0.18.28",
3
+ "version": "0.18.30",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -16,13 +16,13 @@
16
16
  "formik": "2.2.9",
17
17
  "qrcode": "1.5.1",
18
18
  "ethers": "5.7.2",
19
- "@dynamic-labs/logger": "0.18.28",
20
- "@dynamic-labs/multi-wallet": "0.18.28",
21
- "@dynamic-labs/rpc-providers": "0.18.28",
22
- "@dynamic-labs/types": "0.18.28",
23
- "@dynamic-labs/utils": "0.18.28",
24
- "@dynamic-labs/wallet-book": "0.18.28",
25
- "@dynamic-labs/wallet-connector-core": "0.18.28",
19
+ "@dynamic-labs/logger": "0.18.30",
20
+ "@dynamic-labs/multi-wallet": "0.18.30",
21
+ "@dynamic-labs/rpc-providers": "0.18.30",
22
+ "@dynamic-labs/types": "0.18.30",
23
+ "@dynamic-labs/utils": "0.18.30",
24
+ "@dynamic-labs/wallet-book": "0.18.30",
25
+ "@dynamic-labs/wallet-connector-core": "0.18.30",
26
26
  "eventemitter3": "5.0.1"
27
27
  },
28
28
  "devDependencies": {
@@ -190,6 +190,7 @@ const DynamicContextProvider = ({ children, theme, settings, }) => {
190
190
  clearPrimaryWalletId,
191
191
  enableVisitTrackingOnConnectOnly,
192
192
  environmentId,
193
+ isBridgeFlow,
193
194
  onBeforeConnectSuccessConfirmation: eventsCallbacks === null || eventsCallbacks === void 0 ? void 0 : eventsCallbacks.onBeforeConnectSuccessConfirmation,
194
195
  onUnlink: (walletId, connectedWalletsInfo) => {
195
196
  const missingChains = getMissingChains.getMissingChains(walletsByChain, connectedWalletsInfo);
@@ -186,6 +186,7 @@ const DynamicContextProvider = ({ children, theme, settings, }) => {
186
186
  clearPrimaryWalletId,
187
187
  enableVisitTrackingOnConnectOnly,
188
188
  environmentId,
189
+ isBridgeFlow,
189
190
  onBeforeConnectSuccessConfirmation: eventsCallbacks === null || eventsCallbacks === void 0 ? void 0 : eventsCallbacks.onBeforeConnectSuccessConfirmation,
190
191
  onUnlink: (walletId, connectedWalletsInfo) => {
191
192
  const missingChains = getMissingChains(walletsByChain, connectedWalletsInfo);
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const getProviderByType = (providers, providerType) => providers.find((p) => p.provider === providerType);
6
+
7
+ exports.getProviderByType = getProviderByType;
@@ -0,0 +1,2 @@
1
+ import { Provider, ProviderEnum } from '@dynamic-labs/sdk-api';
2
+ export declare const getProviderByType: (providers: Provider[], providerType: ProviderEnum) => Provider | undefined;
@@ -0,0 +1,3 @@
1
+ const getProviderByType = (providers, providerType) => providers.find((p) => p.provider === providerType);
2
+
3
+ export { getProviderByType };
@@ -0,0 +1 @@
1
+ export { getProviderByType } from './getProviderByType';
@@ -28,3 +28,4 @@ export * from './digestSHA256';
28
28
  export * from './encodeBase64URL';
29
29
  export * from './getRedirectURIOrigin';
30
30
  export * from './sendTransactionWithAutoNonce';
31
+ export * from './getProviderByType';
@@ -23,9 +23,35 @@ var api = require('../../../data/api.cjs');
23
23
  require('@dynamic-labs/multi-wallet');
24
24
  var shouldManuallyReconnectOnRefresh = require('../../functions/shouldManuallyReconnectOnRefresh/shouldManuallyReconnectOnRefresh.cjs');
25
25
 
26
- const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId, setPrimaryWalletId, wallets, onUnlink, onBeforeConnectSuccessConfirmation, setShowAuthFlow, }) => {
26
+ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId, setPrimaryWalletId, wallets, onUnlink, onBeforeConnectSuccessConfirmation, setShowAuthFlow, isBridgeFlow, }) => {
27
27
  const [connectedWalletsInfo, setConnectedWalletsInfo, removeConnectedWalletsInfo,] = useLocalStorage.useLocalStorage(localStorage.CONNECTED_WALLETS_INFO, []);
28
28
  const [connectedWallets, setConnectedWallets] = React.useState([]);
29
+ const unlinkConnectedWallet = React.useCallback((walletId) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
30
+ const connectedWalletToUnlink = connectedWallets.find((wallet) => wallet.id === walletId);
31
+ yield (connectedWalletToUnlink === null || connectedWalletToUnlink === void 0 ? void 0 : connectedWalletToUnlink.connector.endSession());
32
+ const filteredWallets = connectedWalletsInfo.filter((wallet) => wallet.id !== walletId);
33
+ setConnectedWalletsInfo(filteredWallets);
34
+ onUnlink === null || onUnlink === void 0 ? void 0 : onUnlink(walletId, filteredWallets);
35
+ if (walletId !== primaryWalletId) {
36
+ return;
37
+ }
38
+ const hasConnectedWallet = filteredWallets.length > 0;
39
+ if (isBridgeFlow || !hasConnectedWallet) {
40
+ clearPrimaryWalletId();
41
+ }
42
+ else {
43
+ setPrimaryWalletId(filteredWallets[0].id);
44
+ }
45
+ }), [
46
+ clearPrimaryWalletId,
47
+ connectedWallets,
48
+ connectedWalletsInfo,
49
+ isBridgeFlow,
50
+ onUnlink,
51
+ primaryWalletId,
52
+ setConnectedWalletsInfo,
53
+ setPrimaryWalletId,
54
+ ]);
29
55
  // The function to update and define the connectedWallets list.
30
56
  // It uses walletConnector to get the current wallet address and network
31
57
  // The address and network in the runtime are updated by the event listeners
@@ -41,9 +67,14 @@ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingO
41
67
  if (!walletConnector) {
42
68
  walletConnectorCore.logger.error('Could not find walletConnector: ' +
43
69
  storedConnectedWalletInfo.walletConnectorKey);
70
+ yield unlinkConnectedWallet(storedConnectedWalletInfo.id);
44
71
  return Promise.resolve(null);
45
72
  }
46
73
  const [walletAddress] = yield walletConnector.getConnectedAccounts();
74
+ if (!walletAddress) {
75
+ yield unlinkConnectedWallet(storedConnectedWalletInfo.id);
76
+ return null;
77
+ }
47
78
  const walletNetwork = yield walletConnector.getNetwork();
48
79
  const walletChain = walletConnector.connectedChain;
49
80
  const walletObject = {
@@ -57,11 +88,12 @@ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingO
57
88
  return Promise.resolve(walletObject);
58
89
  })))).filter((wallet) => Boolean(wallet));
59
90
  setConnectedWallets(nextConnectedWallets);
60
- }), [connectedWalletsInfo, wallets]);
91
+ }), [connectedWalletsInfo, unlinkConnectedWallet, wallets]);
61
92
  // Generate the connectedWallets list when connectedWalletsInfo (localStorage) or memoized wallet connector updates
62
93
  React.useEffect(() => {
63
94
  updateConnectedWalletsList();
64
- }, [updateConnectedWalletsList]);
95
+ // eslint-disable-next-line react-hooks/exhaustive-deps
96
+ }, [connectedWalletsInfo, wallets]);
65
97
  const getNextIdAvailable = React.useCallback((currentWallets) => {
66
98
  const existingIds = currentWallets.map(({ id }) => id);
67
99
  const sortedIds = existingIds
@@ -173,16 +205,6 @@ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingO
173
205
  }
174
206
  return Promise.resolve(publicWalletAddress);
175
207
  });
176
- const unlinkConnectedWallet = (walletId) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
177
- const connectedWalletToUnlink = connectedWallets.find((wallet) => wallet.id === walletId);
178
- yield (connectedWalletToUnlink === null || connectedWalletToUnlink === void 0 ? void 0 : connectedWalletToUnlink.connector.endSession());
179
- const filteredWallets = connectedWalletsInfo.filter((wallet) => wallet.id !== walletId);
180
- if (walletId === primaryWalletId) {
181
- clearPrimaryWalletId();
182
- }
183
- setConnectedWalletsInfo(filteredWallets);
184
- onUnlink === null || onUnlink === void 0 ? void 0 : onUnlink(walletId, filteredWallets);
185
- });
186
208
  const getConnectedWalletById = React.useCallback((walletId) => connectedWallets.find((wallet) => wallet.id === walletId), [connectedWallets]);
187
209
  return {
188
210
  connectWallet,
@@ -18,8 +18,9 @@ type Props = {
18
18
  onUnlink?: (walletId: string, connectedWalletsInfo: ConnectedWalletConnectorType[]) => void;
19
19
  onBeforeConnectSuccessConfirmation: OnBeforeConnectSuccessConfirmation | undefined;
20
20
  setShowAuthFlow: Dispatch<SetStateAction<boolean>>;
21
+ isBridgeFlow: boolean;
21
22
  };
22
- export declare const useConnectWallet: ({ authMode, clearPrimaryWalletId, enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId, setPrimaryWalletId, wallets, onUnlink, onBeforeConnectSuccessConfirmation, setShowAuthFlow, }: Props) => {
23
+ export declare const useConnectWallet: ({ authMode, clearPrimaryWalletId, enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId, setPrimaryWalletId, wallets, onUnlink, onBeforeConnectSuccessConfirmation, setShowAuthFlow, isBridgeFlow, }: Props) => {
23
24
  connectWallet: (walletConnector: WalletConnector, fetchPublicAddressOpts?: FetchPublicAddressOpts, shouldCallCallback?: boolean) => Promise<string | undefined>;
24
25
  connectedWallet: Wallet;
25
26
  connectedWallets: Wallet[];
@@ -19,9 +19,35 @@ import { createVisit } from '../../../data/api.js';
19
19
  import '@dynamic-labs/multi-wallet';
20
20
  import { shouldManuallyReconnectOnRefresh } from '../../functions/shouldManuallyReconnectOnRefresh/shouldManuallyReconnectOnRefresh.js';
21
21
 
22
- const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId, setPrimaryWalletId, wallets, onUnlink, onBeforeConnectSuccessConfirmation, setShowAuthFlow, }) => {
22
+ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId, setPrimaryWalletId, wallets, onUnlink, onBeforeConnectSuccessConfirmation, setShowAuthFlow, isBridgeFlow, }) => {
23
23
  const [connectedWalletsInfo, setConnectedWalletsInfo, removeConnectedWalletsInfo,] = useLocalStorage(CONNECTED_WALLETS_INFO, []);
24
24
  const [connectedWallets, setConnectedWallets] = useState([]);
25
+ const unlinkConnectedWallet = useCallback((walletId) => __awaiter(void 0, void 0, void 0, function* () {
26
+ const connectedWalletToUnlink = connectedWallets.find((wallet) => wallet.id === walletId);
27
+ yield (connectedWalletToUnlink === null || connectedWalletToUnlink === void 0 ? void 0 : connectedWalletToUnlink.connector.endSession());
28
+ const filteredWallets = connectedWalletsInfo.filter((wallet) => wallet.id !== walletId);
29
+ setConnectedWalletsInfo(filteredWallets);
30
+ onUnlink === null || onUnlink === void 0 ? void 0 : onUnlink(walletId, filteredWallets);
31
+ if (walletId !== primaryWalletId) {
32
+ return;
33
+ }
34
+ const hasConnectedWallet = filteredWallets.length > 0;
35
+ if (isBridgeFlow || !hasConnectedWallet) {
36
+ clearPrimaryWalletId();
37
+ }
38
+ else {
39
+ setPrimaryWalletId(filteredWallets[0].id);
40
+ }
41
+ }), [
42
+ clearPrimaryWalletId,
43
+ connectedWallets,
44
+ connectedWalletsInfo,
45
+ isBridgeFlow,
46
+ onUnlink,
47
+ primaryWalletId,
48
+ setConnectedWalletsInfo,
49
+ setPrimaryWalletId,
50
+ ]);
25
51
  // The function to update and define the connectedWallets list.
26
52
  // It uses walletConnector to get the current wallet address and network
27
53
  // The address and network in the runtime are updated by the event listeners
@@ -37,9 +63,14 @@ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingO
37
63
  if (!walletConnector) {
38
64
  logger.error('Could not find walletConnector: ' +
39
65
  storedConnectedWalletInfo.walletConnectorKey);
66
+ yield unlinkConnectedWallet(storedConnectedWalletInfo.id);
40
67
  return Promise.resolve(null);
41
68
  }
42
69
  const [walletAddress] = yield walletConnector.getConnectedAccounts();
70
+ if (!walletAddress) {
71
+ yield unlinkConnectedWallet(storedConnectedWalletInfo.id);
72
+ return null;
73
+ }
43
74
  const walletNetwork = yield walletConnector.getNetwork();
44
75
  const walletChain = walletConnector.connectedChain;
45
76
  const walletObject = {
@@ -53,11 +84,12 @@ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingO
53
84
  return Promise.resolve(walletObject);
54
85
  })))).filter((wallet) => Boolean(wallet));
55
86
  setConnectedWallets(nextConnectedWallets);
56
- }), [connectedWalletsInfo, wallets]);
87
+ }), [connectedWalletsInfo, unlinkConnectedWallet, wallets]);
57
88
  // Generate the connectedWallets list when connectedWalletsInfo (localStorage) or memoized wallet connector updates
58
89
  useEffect(() => {
59
90
  updateConnectedWalletsList();
60
- }, [updateConnectedWalletsList]);
91
+ // eslint-disable-next-line react-hooks/exhaustive-deps
92
+ }, [connectedWalletsInfo, wallets]);
61
93
  const getNextIdAvailable = useCallback((currentWallets) => {
62
94
  const existingIds = currentWallets.map(({ id }) => id);
63
95
  const sortedIds = existingIds
@@ -169,16 +201,6 @@ const useConnectWallet = ({ authMode, clearPrimaryWalletId, enableVisitTrackingO
169
201
  }
170
202
  return Promise.resolve(publicWalletAddress);
171
203
  });
172
- const unlinkConnectedWallet = (walletId) => __awaiter(void 0, void 0, void 0, function* () {
173
- const connectedWalletToUnlink = connectedWallets.find((wallet) => wallet.id === walletId);
174
- yield (connectedWalletToUnlink === null || connectedWalletToUnlink === void 0 ? void 0 : connectedWalletToUnlink.connector.endSession());
175
- const filteredWallets = connectedWalletsInfo.filter((wallet) => wallet.id !== walletId);
176
- if (walletId === primaryWalletId) {
177
- clearPrimaryWalletId();
178
- }
179
- setConnectedWalletsInfo(filteredWallets);
180
- onUnlink === null || onUnlink === void 0 ? void 0 : onUnlink(walletId, filteredWallets);
181
- });
182
204
  const getConnectedWalletById = useCallback((walletId) => connectedWallets.find((wallet) => wallet.id === walletId), [connectedWallets]);
183
205
  return {
184
206
  connectWallet,
@@ -25,10 +25,10 @@ const usePrimaryWalletId = (internalEvents) => {
25
25
  const setPrimaryWalletId = React.useCallback((walletId) => {
26
26
  setPrimaryWalletIdState(walletId);
27
27
  }, [setPrimaryWalletIdState]);
28
- const clearPrimaryWalletId = () => {
28
+ const clearPrimaryWalletId = React.useCallback(() => {
29
29
  clearPrimaryWalletIdStorage();
30
30
  internalEvents.emit('clearPrimaryWallet');
31
- };
31
+ }, [clearPrimaryWalletIdStorage, internalEvents]);
32
32
  return {
33
33
  clearPrimaryWalletId,
34
34
  primaryWalletId,
@@ -21,10 +21,10 @@ const usePrimaryWalletId = (internalEvents) => {
21
21
  const setPrimaryWalletId = useCallback((walletId) => {
22
22
  setPrimaryWalletIdState(walletId);
23
23
  }, [setPrimaryWalletIdState]);
24
- const clearPrimaryWalletId = () => {
24
+ const clearPrimaryWalletId = useCallback(() => {
25
25
  clearPrimaryWalletIdStorage();
26
26
  internalEvents.emit('clearPrimaryWallet');
27
- };
27
+ }, [clearPrimaryWalletIdStorage, internalEvents]);
28
28
  return {
29
29
  clearPrimaryWalletId,
30
30
  primaryWalletId,
@@ -29,6 +29,7 @@ var stringifyURIQuery = require('../../functions/stringifyURIQuery/stringifyURIQ
29
29
  var digestSHA256 = require('../../functions/digestSHA256/digestSHA256.cjs');
30
30
  var encodeBase64URL = require('../../functions/encodeBase64URL/encodeBase64URL.cjs');
31
31
  var getRedirectURIOrigin = require('../../functions/getRedirectURIOrigin/getRedirectURIOrigin.cjs');
32
+ var getProviderByType = require('../../functions/getProviderByType/getProviderByType.cjs');
32
33
 
33
34
  const socialProviders = [
34
35
  'discord',
@@ -136,28 +137,60 @@ const useSocialAccounts = ({ sessionTimeout } = {
136
137
  providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: false });
137
138
  };
138
139
  const handleAuthWindowMessage = (event) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
139
- var _c;
140
+ var _c, _d;
140
141
  const message = event.data;
142
+ const apiProvider = getProviderByType.getProviderByType((_c = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _c !== void 0 ? _c : [], provider);
143
+ if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
144
+ return;
145
+ }
146
+ let expectedOrigin = '';
147
+ try {
148
+ const redirectUri = new URL(apiProvider.redirectUrl);
149
+ expectedOrigin = redirectUri.origin;
150
+ }
151
+ catch (e) {
152
+ logger.logger.error('Failed to parse social provider redirect url', {
153
+ error: e,
154
+ });
155
+ return;
156
+ }
157
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'origin_check' && authWindow) {
158
+ logger.logger.debug('Origin check message received. Sending response now.', {
159
+ data: message,
160
+ expectedOrigin,
161
+ });
162
+ authWindow.postMessage('origin_check_response', expectedOrigin);
163
+ return;
164
+ }
141
165
  const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
142
166
  if (isAuthorizationMessage) {
143
167
  logger.logger.debug('Message received', { data: message });
144
168
  }
145
- const isValidMessage = isAuthorizationMessage && (message === null || message === void 0 ? void 0 : message.provider) === provider;
169
+ const isExpectedOrigin = event.origin === expectedOrigin;
170
+ const isValidMessage = isAuthorizationMessage &&
171
+ (message === null || message === void 0 ? void 0 : message.provider) === provider &&
172
+ isExpectedOrigin;
146
173
  // don't process imvalid messages for provider
147
174
  if (!isValidMessage) {
148
175
  return;
149
176
  }
150
177
  setIsProcessing(true);
151
- if (!((_c = providersWaitingOauthMessages.current) === null || _c === void 0 ? void 0 : _c[provider])) {
178
+ if (!((_d = providersWaitingOauthMessages.current) === null || _d === void 0 ? void 0 : _d[provider])) {
152
179
  handleError(`Linking ${provider} account session timeout.`);
153
180
  return;
154
181
  }
155
182
  clearListeners();
156
- const { code, error } = message;
183
+ const { code, error, state: authState } = message;
157
184
  if (error && error !== 'undefined') {
158
185
  handleError(`Failed to link ${provider} social account: ${error}`);
159
186
  return;
160
187
  }
188
+ // check that the state we receive from message is the same state we calculated earlier
189
+ // this could be an attack
190
+ if (state !== authState) {
191
+ handleError(`Failed to link ${provider} social account: invalid auth state`);
192
+ return;
193
+ }
161
194
  if (!code) {
162
195
  handleError(`Failed to link ${provider} social account: no authorization code`);
163
196
  return;
@@ -184,19 +217,23 @@ const useSocialAccounts = ({ sessionTimeout } = {
184
217
  // different origins (our api redirect page and the app where the sdk is running)
185
218
  const oauthIFrameUrl = `${getRedirectURIOrigin.getRedirectURIOrigin(loginUrl)}/sdkoauth`;
186
219
  addOAuthIFrame(oauthIFrameUrl);
187
- let oauthLoginUrl = loginUrl;
220
+ if (!((_b = providersWaitingOauthMessages.current) === null || _b === void 0 ? void 0 : _b[provider])) {
221
+ window.addEventListener('message', handleAuthWindowMessage);
222
+ providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: true });
223
+ }
224
+ // add state param for all providers
225
+ const stateParam = stringifyURIQuery.stringifyURIQuery({
226
+ state,
227
+ });
228
+ let oauthLoginUrl = `${loginUrl}&${stateParam}`;
229
+ // only add pkce params for providers that support/require it
188
230
  if (providersRequiringPkce.includes(provider)) {
189
231
  const digest = yield digestSHA256.digestSHA256(verifier);
190
232
  const pkceParams = stringifyURIQuery.stringifyURIQuery({
191
233
  code_challenge: encodeBase64URL.encodeBase64URL(digest),
192
234
  code_challenge_method: 'S256',
193
- state: state,
194
235
  });
195
- oauthLoginUrl = `${loginUrl}&${pkceParams}`;
196
- }
197
- if (!((_b = providersWaitingOauthMessages.current) === null || _b === void 0 ? void 0 : _b[provider])) {
198
- window.addEventListener('message', handleAuthWindowMessage);
199
- providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: true });
236
+ oauthLoginUrl = `${oauthLoginUrl}&${pkceParams}`;
200
237
  }
201
238
  const authWindow = window.open(oauthLoginUrl, '_blank', 'width=500,height=600');
202
239
  if (!providersWithoutWindowOpenerRefence.includes(provider)) {
@@ -225,7 +262,7 @@ const useSocialAccounts = ({ sessionTimeout } = {
225
262
  }
226
263
  });
227
264
  const unlinkSocialAccount = (provider) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
228
- var _d;
265
+ var _e;
229
266
  setError(undefined);
230
267
  setIsProcessing(true);
231
268
  if (!checkValidProvider(provider)) {
@@ -241,7 +278,7 @@ const useSocialAccounts = ({ sessionTimeout } = {
241
278
  const jwt = yield api.unlinkOAuth({
242
279
  environmentId,
243
280
  primaryWalletId,
244
- verifiedCrentialId: (_d = verifiedCredential.id) !== null && _d !== void 0 ? _d : '',
281
+ verifiedCrentialId: (_e = verifiedCredential.id) !== null && _e !== void 0 ? _e : '',
245
282
  }, String(userJwt));
246
283
  if (!jwt) {
247
284
  handleError(`Failed to unlink social account: ${provider} | ${verifiedCredential.id}`);
@@ -25,6 +25,7 @@ import { stringifyURIQuery } from '../../functions/stringifyURIQuery/stringifyUR
25
25
  import { digestSHA256 } from '../../functions/digestSHA256/digestSHA256.js';
26
26
  import { encodeBase64URL } from '../../functions/encodeBase64URL/encodeBase64URL.js';
27
27
  import { getRedirectURIOrigin } from '../../functions/getRedirectURIOrigin/getRedirectURIOrigin.js';
28
+ import { getProviderByType } from '../../functions/getProviderByType/getProviderByType.js';
28
29
 
29
30
  const socialProviders = [
30
31
  'discord',
@@ -132,28 +133,60 @@ const useSocialAccounts = ({ sessionTimeout } = {
132
133
  providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: false });
133
134
  };
134
135
  const handleAuthWindowMessage = (event) => __awaiter(void 0, void 0, void 0, function* () {
135
- var _c;
136
+ var _c, _d;
136
137
  const message = event.data;
138
+ const apiProvider = getProviderByType((_c = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _c !== void 0 ? _c : [], provider);
139
+ if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
140
+ return;
141
+ }
142
+ let expectedOrigin = '';
143
+ try {
144
+ const redirectUri = new URL(apiProvider.redirectUrl);
145
+ expectedOrigin = redirectUri.origin;
146
+ }
147
+ catch (e) {
148
+ logger.error('Failed to parse social provider redirect url', {
149
+ error: e,
150
+ });
151
+ return;
152
+ }
153
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'origin_check' && authWindow) {
154
+ logger.debug('Origin check message received. Sending response now.', {
155
+ data: message,
156
+ expectedOrigin,
157
+ });
158
+ authWindow.postMessage('origin_check_response', expectedOrigin);
159
+ return;
160
+ }
137
161
  const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
138
162
  if (isAuthorizationMessage) {
139
163
  logger.debug('Message received', { data: message });
140
164
  }
141
- const isValidMessage = isAuthorizationMessage && (message === null || message === void 0 ? void 0 : message.provider) === provider;
165
+ const isExpectedOrigin = event.origin === expectedOrigin;
166
+ const isValidMessage = isAuthorizationMessage &&
167
+ (message === null || message === void 0 ? void 0 : message.provider) === provider &&
168
+ isExpectedOrigin;
142
169
  // don't process imvalid messages for provider
143
170
  if (!isValidMessage) {
144
171
  return;
145
172
  }
146
173
  setIsProcessing(true);
147
- if (!((_c = providersWaitingOauthMessages.current) === null || _c === void 0 ? void 0 : _c[provider])) {
174
+ if (!((_d = providersWaitingOauthMessages.current) === null || _d === void 0 ? void 0 : _d[provider])) {
148
175
  handleError(`Linking ${provider} account session timeout.`);
149
176
  return;
150
177
  }
151
178
  clearListeners();
152
- const { code, error } = message;
179
+ const { code, error, state: authState } = message;
153
180
  if (error && error !== 'undefined') {
154
181
  handleError(`Failed to link ${provider} social account: ${error}`);
155
182
  return;
156
183
  }
184
+ // check that the state we receive from message is the same state we calculated earlier
185
+ // this could be an attack
186
+ if (state !== authState) {
187
+ handleError(`Failed to link ${provider} social account: invalid auth state`);
188
+ return;
189
+ }
157
190
  if (!code) {
158
191
  handleError(`Failed to link ${provider} social account: no authorization code`);
159
192
  return;
@@ -180,19 +213,23 @@ const useSocialAccounts = ({ sessionTimeout } = {
180
213
  // different origins (our api redirect page and the app where the sdk is running)
181
214
  const oauthIFrameUrl = `${getRedirectURIOrigin(loginUrl)}/sdkoauth`;
182
215
  addOAuthIFrame(oauthIFrameUrl);
183
- let oauthLoginUrl = loginUrl;
216
+ if (!((_b = providersWaitingOauthMessages.current) === null || _b === void 0 ? void 0 : _b[provider])) {
217
+ window.addEventListener('message', handleAuthWindowMessage);
218
+ providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: true });
219
+ }
220
+ // add state param for all providers
221
+ const stateParam = stringifyURIQuery({
222
+ state,
223
+ });
224
+ let oauthLoginUrl = `${loginUrl}&${stateParam}`;
225
+ // only add pkce params for providers that support/require it
184
226
  if (providersRequiringPkce.includes(provider)) {
185
227
  const digest = yield digestSHA256(verifier);
186
228
  const pkceParams = stringifyURIQuery({
187
229
  code_challenge: encodeBase64URL(digest),
188
230
  code_challenge_method: 'S256',
189
- state: state,
190
231
  });
191
- oauthLoginUrl = `${loginUrl}&${pkceParams}`;
192
- }
193
- if (!((_b = providersWaitingOauthMessages.current) === null || _b === void 0 ? void 0 : _b[provider])) {
194
- window.addEventListener('message', handleAuthWindowMessage);
195
- providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: true });
232
+ oauthLoginUrl = `${oauthLoginUrl}&${pkceParams}`;
196
233
  }
197
234
  const authWindow = window.open(oauthLoginUrl, '_blank', 'width=500,height=600');
198
235
  if (!providersWithoutWindowOpenerRefence.includes(provider)) {
@@ -221,7 +258,7 @@ const useSocialAccounts = ({ sessionTimeout } = {
221
258
  }
222
259
  });
223
260
  const unlinkSocialAccount = (provider) => __awaiter(void 0, void 0, void 0, function* () {
224
- var _d;
261
+ var _e;
225
262
  setError(undefined);
226
263
  setIsProcessing(true);
227
264
  if (!checkValidProvider(provider)) {
@@ -237,7 +274,7 @@ const useSocialAccounts = ({ sessionTimeout } = {
237
274
  const jwt = yield unlinkOAuth({
238
275
  environmentId,
239
276
  primaryWalletId,
240
- verifiedCrentialId: (_d = verifiedCredential.id) !== null && _d !== void 0 ? _d : '',
277
+ verifiedCrentialId: (_e = verifiedCredential.id) !== null && _e !== void 0 ? _e : '',
241
278
  }, String(userJwt));
242
279
  if (!jwt) {
243
280
  handleError(`Failed to unlink social account: ${provider} | ${verifiedCredential.id}`);