@dynamic-labs/sdk-react-core 0.18.100-viem.1 → 0.18.100-viem.10

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/package.cjs +3 -3
  3. package/package.js +3 -3
  4. package/package.json +10 -10
  5. package/src/index.cjs +2 -0
  6. package/src/index.js +1 -0
  7. package/src/lib/components/MenuList/Dropdown/Dropdown.cjs +1 -1
  8. package/src/lib/components/MenuList/Dropdown/Dropdown.js +1 -1
  9. package/src/lib/components/ModalHeaderBanner/ModalHeaderBanner.cjs +6 -2
  10. package/src/lib/components/ModalHeaderBanner/ModalHeaderBanner.d.ts +2 -1
  11. package/src/lib/components/ModalHeaderBanner/ModalHeaderBanner.js +6 -2
  12. package/src/lib/components/OTPVerificationView/OTPVerificationView.cjs +2 -2
  13. package/src/lib/components/OTPVerificationView/OTPVerificationView.d.ts +1 -0
  14. package/src/lib/components/OTPVerificationView/OTPVerificationView.js +2 -2
  15. package/src/lib/components/Typography/Typography.cjs +1 -0
  16. package/src/lib/components/Typography/Typography.js +1 -0
  17. package/src/lib/components/Typography/Typography.types.d.ts +1 -1
  18. package/src/lib/components/UserProfile/UserProfile.cjs +1 -1
  19. package/src/lib/components/UserProfile/UserProfile.js +1 -1
  20. package/src/lib/components/UserProfile/parts/UserProfileSocialAccount/UserProfileSocialAccount.cjs +1 -1
  21. package/src/lib/components/UserProfile/parts/UserProfileSocialAccount/UserProfileSocialAccount.js +1 -1
  22. package/src/lib/context/DynamicContext/DynamicContext.cjs +8 -2
  23. package/src/lib/context/DynamicContext/DynamicContext.js +9 -3
  24. package/src/lib/context/DynamicContext/internalEvents/index.d.ts +2 -0
  25. package/src/lib/context/DynamicContext/internalEvents/internalEvents.cjs +14 -0
  26. package/src/lib/context/DynamicContext/internalEvents/internalEvents.d.ts +8 -0
  27. package/src/lib/context/DynamicContext/internalEvents/internalEvents.js +6 -0
  28. package/src/lib/context/DynamicContext/types/index.d.ts +4 -1
  29. package/src/lib/context/DynamicContext/useDynamicContext.cjs +2 -1
  30. package/src/lib/context/DynamicContext/useDynamicContext.d.ts +1 -1
  31. package/src/lib/context/DynamicContext/useDynamicContext.js +2 -1
  32. package/src/lib/context/SocialRedirectContext/SocialRedirectContext.cjs +2 -1
  33. package/src/lib/context/SocialRedirectContext/SocialRedirectContext.js +2 -1
  34. package/src/lib/data/api.cjs +17 -1
  35. package/src/lib/data/api.d.ts +2 -1
  36. package/src/lib/data/api.js +17 -2
  37. package/src/lib/main.global.cjs +1 -1
  38. package/src/lib/main.global.js +1 -1
  39. package/src/lib/modals/TransactionConfirmationModal/TransactionConfirmationModal.cjs +2 -1
  40. package/src/lib/modals/TransactionConfirmationModal/TransactionConfirmationModal.js +2 -1
  41. package/src/lib/shared/utils/hooks/usePreventPageScroll/usePreventPageScroll.cjs +28 -2
  42. package/src/lib/shared/utils/hooks/usePreventPageScroll/usePreventPageScroll.js +28 -2
  43. package/src/lib/styles/index.shadow.cjs +1 -1
  44. package/src/lib/styles/index.shadow.js +1 -1
  45. package/src/lib/utils/functions/createUserProfile/createUserProfile.cjs +1 -1
  46. package/src/lib/utils/functions/createUserProfile/createUserProfile.js +1 -1
  47. package/src/lib/utils/functions/digestSHA256/digestSHA256.cjs +11 -0
  48. package/src/lib/utils/functions/digestSHA256/digestSHA256.d.ts +1 -0
  49. package/src/lib/utils/functions/digestSHA256/digestSHA256.js +7 -0
  50. package/src/lib/utils/functions/digestSHA256/index.d.ts +1 -0
  51. package/src/lib/utils/functions/encodeBase64URL/encodeBase64URL.cjs +14 -0
  52. package/src/lib/utils/functions/encodeBase64URL/encodeBase64URL.d.ts +1 -0
  53. package/src/lib/utils/functions/encodeBase64URL/encodeBase64URL.js +10 -0
  54. package/src/lib/utils/functions/encodeBase64URL/index.d.ts +1 -0
  55. package/src/lib/utils/functions/getRedirectURIOrigin/getRedirectURIOrigin.cjs +33 -0
  56. package/src/lib/utils/functions/getRedirectURIOrigin/getRedirectURIOrigin.d.ts +1 -0
  57. package/src/lib/utils/functions/getRedirectURIOrigin/getRedirectURIOrigin.js +29 -0
  58. package/src/lib/utils/functions/getRedirectURIOrigin/index.d.ts +1 -0
  59. package/src/lib/utils/functions/index.d.ts +6 -0
  60. package/src/lib/utils/functions/randomString/index.d.ts +1 -0
  61. package/src/lib/utils/functions/randomString/randomString.cjs +14 -0
  62. package/src/lib/utils/functions/randomString/randomString.d.ts +1 -0
  63. package/src/lib/utils/functions/randomString/randomString.js +10 -0
  64. package/src/lib/utils/functions/sendTransactionWithAutoNonce/index.d.ts +1 -0
  65. package/src/lib/utils/functions/sendTransactionWithAutoNonce/sendTransactionWithAutoNonce.cjs +48 -0
  66. package/src/lib/utils/functions/sendTransactionWithAutoNonce/sendTransactionWithAutoNonce.d.ts +18 -0
  67. package/src/lib/utils/functions/sendTransactionWithAutoNonce/sendTransactionWithAutoNonce.js +43 -0
  68. package/src/lib/utils/functions/stringifyURIQuery/index.d.ts +1 -0
  69. package/src/lib/utils/functions/stringifyURIQuery/stringifyURIQuery.cjs +13 -0
  70. package/src/lib/utils/functions/stringifyURIQuery/stringifyURIQuery.d.ts +1 -0
  71. package/src/lib/utils/functions/stringifyURIQuery/stringifyURIQuery.js +9 -0
  72. package/src/lib/utils/hooks/authenticationHooks/useConnectAndSign/useConnectAndSign.cjs +8 -2
  73. package/src/lib/utils/hooks/authenticationHooks/useConnectAndSign/useConnectAndSign.js +9 -3
  74. package/src/lib/utils/hooks/multiWallet/useSyncPrimaryWallet/useSyncPrimaryWallet.cjs +4 -0
  75. package/src/lib/utils/hooks/multiWallet/useSyncPrimaryWallet/useSyncPrimaryWallet.js +4 -0
  76. package/src/lib/utils/hooks/useConnectWallet/useConnectWallet.cjs +14 -16
  77. package/src/lib/utils/hooks/useConnectWallet/useConnectWallet.js +15 -17
  78. package/src/lib/utils/hooks/useConnectedWalletsNetworkValidation/useConnectedWalletsNetworkValidation.cjs +7 -6
  79. package/src/lib/utils/hooks/useConnectedWalletsNetworkValidation/useConnectedWalletsNetworkValidation.js +7 -6
  80. package/src/lib/utils/hooks/usePrimaryWalletId/usePrimaryWalletId.cjs +6 -2
  81. package/src/lib/utils/hooks/usePrimaryWalletId/usePrimaryWalletId.d.ts +2 -1
  82. package/src/lib/utils/hooks/usePrimaryWalletId/usePrimaryWalletId.js +6 -2
  83. package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.cjs +128 -23
  84. package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.d.ts +5 -1
  85. package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.js +130 -25
  86. package/src/lib/views/CaptchaVerifyUser/CaptchaVerifyUser.cjs +9 -3
  87. package/src/lib/views/CaptchaVerifyUser/CaptchaVerifyUser.js +9 -3
  88. package/src/lib/views/EmailWalletOTPVerificationView/EmailWalletOTPVerificationView.cjs +1 -1
  89. package/src/lib/views/EmailWalletOTPVerificationView/EmailWalletOTPVerificationView.js +1 -1
  90. package/src/lib/views/NetworkNotSupported/NetworkNotSupported.cjs +3 -2
  91. package/src/lib/views/NetworkNotSupported/NetworkNotSupported.js +3 -2
  92. package/src/lib/views/NetworkNotSupportedSwitchManual/NetworkNotSupportedSwitchManual.cjs +3 -2
  93. package/src/lib/views/NetworkNotSupportedSwitchManual/NetworkNotSupportedSwitchManual.js +3 -2
  94. package/src/lib/views/SendBalanceView/components/TransactionStage/TransactionStage.cjs +4 -10
  95. package/src/lib/views/SendBalanceView/components/TransactionStage/TransactionStage.js +4 -10
  96. package/src/lib/views/WalletGroupView/components/WalletGroupItem/WalletGroupItem.cjs +1 -0
  97. package/src/lib/views/WalletGroupView/components/WalletGroupItem/WalletGroupItem.js +1 -0
  98. package/src/lib/views/WalletList/WalletListItem/WalletListItem.cjs +1 -1
  99. package/src/lib/views/WalletList/WalletListItem/WalletListItem.js +1 -1
  100. package/src/lib/widgets/DynamicWidget/hooks/useFetchCurrency/useFetchCurrency.cjs +4 -1
  101. package/src/lib/widgets/DynamicWidget/hooks/useFetchCurrency/useFetchCurrency.js +4 -1
  102. package/src/lib/widgets/OAuthIFrameContainer/OAuthIFrameContainer.cjs +13 -0
  103. package/src/lib/widgets/OAuthIFrameContainer/OAuthIFrameContainer.d.ts +2 -0
  104. package/src/lib/widgets/OAuthIFrameContainer/OAuthIFrameContainer.js +9 -0
  105. package/src/lib/widgets/OAuthIFrameContainer/index.d.ts +1 -0
  106. package/src/lib/widgets/index.d.ts +1 -0
@@ -23,6 +23,11 @@ require('@dynamic-labs/multi-wallet');
23
23
  var getAuthToken = require('../../functions/getAuthToken/getAuthToken.cjs');
24
24
  var index = require('../../functions/getEnabledOAuthProviders/index.cjs');
25
25
  var isSocialKycEnabled = require('../../functions/isSocialKycEnabled/isSocialKycEnabled.cjs');
26
+ var randomString = require('../../functions/randomString/randomString.cjs');
27
+ var stringifyURIQuery = require('../../functions/stringifyURIQuery/stringifyURIQuery.cjs');
28
+ var digestSHA256 = require('../../functions/digestSHA256/digestSHA256.cjs');
29
+ var encodeBase64URL = require('../../functions/encodeBase64URL/encodeBase64URL.cjs');
30
+ var getRedirectURIOrigin = require('../../functions/getRedirectURIOrigin/getRedirectURIOrigin.cjs');
26
31
 
27
32
  const socialProviders = [
28
33
  'discord',
@@ -33,12 +38,20 @@ const socialProviders = [
33
38
  'twitch',
34
39
  'twitter',
35
40
  ];
36
- const useSocialAccounts = () => {
41
+ // pkce params are only required for twitter and break if added for other providers, like google
42
+ // so we should only add provider that support pkce to this list
43
+ const providersRequiringPkce = ['twitter', 'github'];
44
+ const providersWithoutWindowOpenerRefence = ['twitter'];
45
+ const useSocialAccounts = ({ sessionTimeout } = {
46
+ sessionTimeout: 10000,
47
+ }) => {
37
48
  var _a;
38
49
  const { environmentId, user, projectSettings, onboardingOnlyJwt } = useInternalDynamicContext.useInternalDynamicContext();
39
50
  const { updateUserProfileByJWT } = useUpdateUserProfileByJWTCallback.useUpdateUserProfileByJWTCallback();
40
51
  const [isProcessing, setIsProcessing] = React.useState(false);
41
52
  const [error, setError] = React.useState();
53
+ const providersWaitingOauthMessages = React.useRef({});
54
+ const authWindowInterval = React.useRef();
42
55
  const userJwt = (_a = getAuthToken.getAuthToken()) !== null && _a !== void 0 ? _a : onboardingOnlyJwt;
43
56
  const oauthProviders = index.getEnabledOAuthProviders(projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers);
44
57
  const verifiedOAuthCredentialsMap = React.useMemo(() => {
@@ -57,6 +70,23 @@ const useSocialAccounts = () => {
57
70
  setIsProcessing(false);
58
71
  setError(message);
59
72
  };
73
+ const addOAuthIFrame = (url) => {
74
+ const container = document.getElementById('oauth-iframe-container');
75
+ let oauthIFrame = document.getElementById('oauth-iframe');
76
+ if (!container || oauthIFrame) {
77
+ return;
78
+ }
79
+ oauthIFrame = document.createElement('iframe');
80
+ oauthIFrame.setAttribute('id', 'oauth-iframe');
81
+ oauthIFrame.setAttribute('src', url);
82
+ container.appendChild(oauthIFrame);
83
+ };
84
+ const removeOAuthIFrame = () => {
85
+ const oauthIFrame = document.getElementById('oauth-iframe');
86
+ if (oauthIFrame) {
87
+ oauthIFrame.remove();
88
+ }
89
+ };
60
90
  const checkValidProvider = (provider) => {
61
91
  if (!provider) {
62
92
  handleError('Provider is required');
@@ -68,38 +98,73 @@ const useSocialAccounts = () => {
68
98
  }
69
99
  return true;
70
100
  };
71
- const linkSocialAccount = (provider) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
72
- setError(undefined);
73
- setIsProcessing(true);
101
+ const checkValidOAuthLinking = (provider) => {
74
102
  if (!isSocialKycEnabled.isSocialKycEnabled(projectSettings)) {
75
103
  handleError('Social linking is not enabled on the dashboard');
76
- return;
104
+ return false;
77
105
  }
78
106
  if (!checkValidProvider(provider)) {
79
- return;
107
+ return false;
80
108
  }
81
109
  const verifiedCredential = verifiedOAuthCredentialsMap[provider];
82
110
  if (verifiedCredential) {
83
111
  handleError(`Account already linked for provider: ${provider}`);
84
- return;
112
+ return false;
85
113
  }
86
114
  const oauthProvider = oauthProviders.find((p) => p.provider === provider);
87
115
  if (!oauthProvider) {
88
116
  handleError(`Provider is not enabled on the dashboard: ${provider}`);
117
+ return false;
118
+ }
119
+ return true;
120
+ };
121
+ const linkSocialAccount = (provider) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
122
+ var _b;
123
+ clearInterval(authWindowInterval.current);
124
+ setError(undefined);
125
+ setIsProcessing(true);
126
+ // invalid linking request
127
+ if (!checkValidOAuthLinking(provider)) {
89
128
  return;
90
129
  }
130
+ const state = randomString.randomString(8);
131
+ const verifier = randomString.randomString(43);
132
+ const clearListeners = () => {
133
+ removeOAuthIFrame();
134
+ window.removeEventListener('message', handleAuthWindowMessage);
135
+ providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: false });
136
+ };
91
137
  const handleAuthWindowMessage = (event) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
92
- var _b, _c, _d;
93
- if (((_b = event.data) === null || _b === void 0 ? void 0 : _b.type) === 'authorization_response') {
94
- logger.logger.debug('Message received', { data: event.data });
138
+ var _c;
139
+ const message = event.data;
140
+ const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
141
+ if (isAuthorizationMessage) {
142
+ logger.logger.debug('Message received', { data: message });
143
+ }
144
+ const isValidMessage = isAuthorizationMessage && (message === null || message === void 0 ? void 0 : message.provider) === provider;
145
+ // don't process imvalid messages for provider
146
+ if (!isValidMessage) {
147
+ return;
148
+ }
149
+ setIsProcessing(true);
150
+ if (!((_c = providersWaitingOauthMessages.current) === null || _c === void 0 ? void 0 : _c[provider])) {
151
+ handleError(`Linking ${provider} account session timeout.`);
152
+ return;
153
+ }
154
+ clearListeners();
155
+ const { code, error } = message;
156
+ if (error && error !== 'undefined') {
157
+ handleError(`Failed to link ${provider} social account: ${error}`);
158
+ return;
95
159
  }
96
- if (((_c = event.data) === null || _c === void 0 ? void 0 : _c.type) !== 'authorization_response' ||
97
- ((_d = event.data) === null || _d === void 0 ? void 0 : _d.provider) !== provider) {
160
+ if (!code) {
161
+ handleError(`Failed to link ${provider} social account: no authorization code`);
98
162
  return;
99
163
  }
100
- const { code } = event.data;
101
164
  const jwt = yield api.verifyOAuth(environmentId, provider, {
102
165
  code,
166
+ codeVerifier: verifier,
167
+ state,
103
168
  }, String(userJwt));
104
169
  if (!jwt) {
105
170
  handleError(`Failed to link social account: ${provider}`);
@@ -108,18 +173,58 @@ const useSocialAccounts = () => {
108
173
  yield updateUserProfileByJWT(jwt);
109
174
  setIsProcessing(false);
110
175
  });
111
- window.addEventListener('message', handleAuthWindowMessage);
112
- const authWindow = window.open(oauthProvider.authorizationUrl, '_blank', 'width=500,height=600');
113
- const authWindowInterval = setInterval(() => {
114
- if (authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed) {
115
- window.removeEventListener('message', handleAuthWindowMessage);
116
- clearInterval(authWindowInterval);
176
+ const loginUrl = yield api.getOauthLoginUrl(environmentId, provider, String(userJwt));
177
+ if (!loginUrl) {
178
+ handleError(`Failed to get login url to link social account: ${provider}`);
179
+ return;
180
+ }
181
+ // we need to use an iframe to be the intermediary in communications between the popup and the sdk
182
+ // because of twitter limitations with accessing the window.opener and BroadcastChannel not working between
183
+ // different origins (our api redirect page and the app where the sdk is running)
184
+ const oauthIFrameUrl = `${getRedirectURIOrigin.getRedirectURIOrigin(loginUrl)}/sdkoauth`;
185
+ addOAuthIFrame(oauthIFrameUrl);
186
+ let oauthLoginUrl = loginUrl;
187
+ if (providersRequiringPkce.includes(provider)) {
188
+ const digest = yield digestSHA256.digestSHA256(verifier);
189
+ const pkceParams = stringifyURIQuery.stringifyURIQuery({
190
+ code_challenge: encodeBase64URL.encodeBase64URL(digest),
191
+ code_challenge_method: 'S256',
192
+ state: state,
193
+ });
194
+ oauthLoginUrl = `${loginUrl}&${pkceParams}`;
195
+ }
196
+ if (!((_b = providersWaitingOauthMessages.current) === null || _b === void 0 ? void 0 : _b[provider])) {
197
+ window.addEventListener('message', handleAuthWindowMessage);
198
+ providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: true });
199
+ }
200
+ const authWindow = window.open(oauthLoginUrl, '_blank', 'width=500,height=600');
201
+ if (!providersWithoutWindowOpenerRefence.includes(provider)) {
202
+ // For provider that support window.opener, we need to clear all states/listeners when the window is closed
203
+ authWindowInterval.current = setInterval(() => {
204
+ if (!(authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed)) {
205
+ return;
206
+ }
207
+ clearInterval(authWindowInterval.current);
117
208
  setIsProcessing(false);
118
- }
119
- }, 1000);
209
+ });
210
+ }
211
+ else {
212
+ // For provider that don't support window.opener, we need to use a timeout to try to detect when the
213
+ // window is closed
214
+ authWindowInterval.current = setInterval(() => {
215
+ var _a;
216
+ // user didn't complete oauth
217
+ if ((_a = providersWaitingOauthMessages.current) === null || _a === void 0 ? void 0 : _a[provider]) {
218
+ clearListeners();
219
+ handleError(`Linking ${provider} account window timeout.`);
220
+ }
221
+ setIsProcessing(false);
222
+ clearInterval(authWindowInterval.current);
223
+ }, sessionTimeout);
224
+ }
120
225
  });
121
226
  const unlinkSocialAccount = (provider) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
122
- var _e;
227
+ var _d;
123
228
  setError(undefined);
124
229
  setIsProcessing(true);
125
230
  if (!checkValidProvider(provider)) {
@@ -133,7 +238,7 @@ const useSocialAccounts = () => {
133
238
  try {
134
239
  const jwt = yield api.unlinkOAuth({
135
240
  environmentId,
136
- verifiedCrentialId: (_e = verifiedCredential.id) !== null && _e !== void 0 ? _e : '',
241
+ verifiedCrentialId: (_d = verifiedCredential.id) !== null && _d !== void 0 ? _d : '',
137
242
  }, String(userJwt));
138
243
  if (!jwt) {
139
244
  handleError(`Failed to unlink social account: ${provider} | ${verifiedCredential.id}`);
@@ -1,6 +1,9 @@
1
1
  import { ProviderEnum } from '@dynamic-labs/sdk-api';
2
2
  import { SocialAccountInformation } from '@dynamic-labs/types';
3
- export declare const useSocialAccounts: () => {
3
+ type UseSocialAccountsProps = {
4
+ sessionTimeout: number;
5
+ };
6
+ export declare const useSocialAccounts: ({ sessionTimeout }?: UseSocialAccountsProps) => {
4
7
  readonly error: string | undefined;
5
8
  readonly getLinkedAccountInformation: (provider: ProviderEnum) => SocialAccountInformation | undefined;
6
9
  readonly isLinked: (provider: ProviderEnum) => boolean;
@@ -8,3 +11,4 @@ export declare const useSocialAccounts: () => {
8
11
  readonly linkSocialAccount: (provider: ProviderEnum) => Promise<void>;
9
12
  readonly unlinkSocialAccount: (provider: ProviderEnum) => Promise<void>;
10
13
  };
14
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
2
- import { useState, useMemo } from 'react';
2
+ import { useState, useRef, useMemo } from 'react';
3
3
  import { useInternalDynamicContext } from '../../../context/DynamicContext/useInternalDynamicContext.js';
4
- import { unlinkOAuth, verifyOAuth } from '../../../data/api.js';
4
+ import { getOauthLoginUrl, unlinkOAuth, verifyOAuth } from '../../../data/api.js';
5
5
  import { useUpdateUserProfileByJWTCallback } from '../useUpdateUserProfileByJWTCallback/useUpdateUserProfileByJWTCallback.js';
6
6
  import '@dynamic-labs/sdk-api';
7
7
  import { logger } from '../../../shared/logger.js';
@@ -19,6 +19,11 @@ import '@dynamic-labs/multi-wallet';
19
19
  import { getAuthToken } from '../../functions/getAuthToken/getAuthToken.js';
20
20
  import { getEnabledOAuthProviders } from '../../functions/getEnabledOAuthProviders/index.js';
21
21
  import { isSocialKycEnabled } from '../../functions/isSocialKycEnabled/isSocialKycEnabled.js';
22
+ import { randomString } from '../../functions/randomString/randomString.js';
23
+ import { stringifyURIQuery } from '../../functions/stringifyURIQuery/stringifyURIQuery.js';
24
+ import { digestSHA256 } from '../../functions/digestSHA256/digestSHA256.js';
25
+ import { encodeBase64URL } from '../../functions/encodeBase64URL/encodeBase64URL.js';
26
+ import { getRedirectURIOrigin } from '../../functions/getRedirectURIOrigin/getRedirectURIOrigin.js';
22
27
 
23
28
  const socialProviders = [
24
29
  'discord',
@@ -29,12 +34,20 @@ const socialProviders = [
29
34
  'twitch',
30
35
  'twitter',
31
36
  ];
32
- const useSocialAccounts = () => {
37
+ // pkce params are only required for twitter and break if added for other providers, like google
38
+ // so we should only add provider that support pkce to this list
39
+ const providersRequiringPkce = ['twitter', 'github'];
40
+ const providersWithoutWindowOpenerRefence = ['twitter'];
41
+ const useSocialAccounts = ({ sessionTimeout } = {
42
+ sessionTimeout: 10000,
43
+ }) => {
33
44
  var _a;
34
45
  const { environmentId, user, projectSettings, onboardingOnlyJwt } = useInternalDynamicContext();
35
46
  const { updateUserProfileByJWT } = useUpdateUserProfileByJWTCallback();
36
47
  const [isProcessing, setIsProcessing] = useState(false);
37
48
  const [error, setError] = useState();
49
+ const providersWaitingOauthMessages = useRef({});
50
+ const authWindowInterval = useRef();
38
51
  const userJwt = (_a = getAuthToken()) !== null && _a !== void 0 ? _a : onboardingOnlyJwt;
39
52
  const oauthProviders = getEnabledOAuthProviders(projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers);
40
53
  const verifiedOAuthCredentialsMap = useMemo(() => {
@@ -53,6 +66,23 @@ const useSocialAccounts = () => {
53
66
  setIsProcessing(false);
54
67
  setError(message);
55
68
  };
69
+ const addOAuthIFrame = (url) => {
70
+ const container = document.getElementById('oauth-iframe-container');
71
+ let oauthIFrame = document.getElementById('oauth-iframe');
72
+ if (!container || oauthIFrame) {
73
+ return;
74
+ }
75
+ oauthIFrame = document.createElement('iframe');
76
+ oauthIFrame.setAttribute('id', 'oauth-iframe');
77
+ oauthIFrame.setAttribute('src', url);
78
+ container.appendChild(oauthIFrame);
79
+ };
80
+ const removeOAuthIFrame = () => {
81
+ const oauthIFrame = document.getElementById('oauth-iframe');
82
+ if (oauthIFrame) {
83
+ oauthIFrame.remove();
84
+ }
85
+ };
56
86
  const checkValidProvider = (provider) => {
57
87
  if (!provider) {
58
88
  handleError('Provider is required');
@@ -64,38 +94,73 @@ const useSocialAccounts = () => {
64
94
  }
65
95
  return true;
66
96
  };
67
- const linkSocialAccount = (provider) => __awaiter(void 0, void 0, void 0, function* () {
68
- setError(undefined);
69
- setIsProcessing(true);
97
+ const checkValidOAuthLinking = (provider) => {
70
98
  if (!isSocialKycEnabled(projectSettings)) {
71
99
  handleError('Social linking is not enabled on the dashboard');
72
- return;
100
+ return false;
73
101
  }
74
102
  if (!checkValidProvider(provider)) {
75
- return;
103
+ return false;
76
104
  }
77
105
  const verifiedCredential = verifiedOAuthCredentialsMap[provider];
78
106
  if (verifiedCredential) {
79
107
  handleError(`Account already linked for provider: ${provider}`);
80
- return;
108
+ return false;
81
109
  }
82
110
  const oauthProvider = oauthProviders.find((p) => p.provider === provider);
83
111
  if (!oauthProvider) {
84
112
  handleError(`Provider is not enabled on the dashboard: ${provider}`);
113
+ return false;
114
+ }
115
+ return true;
116
+ };
117
+ const linkSocialAccount = (provider) => __awaiter(void 0, void 0, void 0, function* () {
118
+ var _b;
119
+ clearInterval(authWindowInterval.current);
120
+ setError(undefined);
121
+ setIsProcessing(true);
122
+ // invalid linking request
123
+ if (!checkValidOAuthLinking(provider)) {
85
124
  return;
86
125
  }
126
+ const state = randomString(8);
127
+ const verifier = randomString(43);
128
+ const clearListeners = () => {
129
+ removeOAuthIFrame();
130
+ window.removeEventListener('message', handleAuthWindowMessage);
131
+ providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: false });
132
+ };
87
133
  const handleAuthWindowMessage = (event) => __awaiter(void 0, void 0, void 0, function* () {
88
- var _b, _c, _d;
89
- if (((_b = event.data) === null || _b === void 0 ? void 0 : _b.type) === 'authorization_response') {
90
- logger.debug('Message received', { data: event.data });
134
+ var _c;
135
+ const message = event.data;
136
+ const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
137
+ if (isAuthorizationMessage) {
138
+ logger.debug('Message received', { data: message });
139
+ }
140
+ const isValidMessage = isAuthorizationMessage && (message === null || message === void 0 ? void 0 : message.provider) === provider;
141
+ // don't process imvalid messages for provider
142
+ if (!isValidMessage) {
143
+ return;
144
+ }
145
+ setIsProcessing(true);
146
+ if (!((_c = providersWaitingOauthMessages.current) === null || _c === void 0 ? void 0 : _c[provider])) {
147
+ handleError(`Linking ${provider} account session timeout.`);
148
+ return;
149
+ }
150
+ clearListeners();
151
+ const { code, error } = message;
152
+ if (error && error !== 'undefined') {
153
+ handleError(`Failed to link ${provider} social account: ${error}`);
154
+ return;
91
155
  }
92
- if (((_c = event.data) === null || _c === void 0 ? void 0 : _c.type) !== 'authorization_response' ||
93
- ((_d = event.data) === null || _d === void 0 ? void 0 : _d.provider) !== provider) {
156
+ if (!code) {
157
+ handleError(`Failed to link ${provider} social account: no authorization code`);
94
158
  return;
95
159
  }
96
- const { code } = event.data;
97
160
  const jwt = yield verifyOAuth(environmentId, provider, {
98
161
  code,
162
+ codeVerifier: verifier,
163
+ state,
99
164
  }, String(userJwt));
100
165
  if (!jwt) {
101
166
  handleError(`Failed to link social account: ${provider}`);
@@ -104,18 +169,58 @@ const useSocialAccounts = () => {
104
169
  yield updateUserProfileByJWT(jwt);
105
170
  setIsProcessing(false);
106
171
  });
107
- window.addEventListener('message', handleAuthWindowMessage);
108
- const authWindow = window.open(oauthProvider.authorizationUrl, '_blank', 'width=500,height=600');
109
- const authWindowInterval = setInterval(() => {
110
- if (authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed) {
111
- window.removeEventListener('message', handleAuthWindowMessage);
112
- clearInterval(authWindowInterval);
172
+ const loginUrl = yield getOauthLoginUrl(environmentId, provider, String(userJwt));
173
+ if (!loginUrl) {
174
+ handleError(`Failed to get login url to link social account: ${provider}`);
175
+ return;
176
+ }
177
+ // we need to use an iframe to be the intermediary in communications between the popup and the sdk
178
+ // because of twitter limitations with accessing the window.opener and BroadcastChannel not working between
179
+ // different origins (our api redirect page and the app where the sdk is running)
180
+ const oauthIFrameUrl = `${getRedirectURIOrigin(loginUrl)}/sdkoauth`;
181
+ addOAuthIFrame(oauthIFrameUrl);
182
+ let oauthLoginUrl = loginUrl;
183
+ if (providersRequiringPkce.includes(provider)) {
184
+ const digest = yield digestSHA256(verifier);
185
+ const pkceParams = stringifyURIQuery({
186
+ code_challenge: encodeBase64URL(digest),
187
+ code_challenge_method: 'S256',
188
+ state: state,
189
+ });
190
+ oauthLoginUrl = `${loginUrl}&${pkceParams}`;
191
+ }
192
+ if (!((_b = providersWaitingOauthMessages.current) === null || _b === void 0 ? void 0 : _b[provider])) {
193
+ window.addEventListener('message', handleAuthWindowMessage);
194
+ providersWaitingOauthMessages.current = Object.assign(Object.assign({}, providersWaitingOauthMessages.current), { [provider]: true });
195
+ }
196
+ const authWindow = window.open(oauthLoginUrl, '_blank', 'width=500,height=600');
197
+ if (!providersWithoutWindowOpenerRefence.includes(provider)) {
198
+ // For provider that support window.opener, we need to clear all states/listeners when the window is closed
199
+ authWindowInterval.current = setInterval(() => {
200
+ if (!(authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed)) {
201
+ return;
202
+ }
203
+ clearInterval(authWindowInterval.current);
113
204
  setIsProcessing(false);
114
- }
115
- }, 1000);
205
+ });
206
+ }
207
+ else {
208
+ // For provider that don't support window.opener, we need to use a timeout to try to detect when the
209
+ // window is closed
210
+ authWindowInterval.current = setInterval(() => {
211
+ var _a;
212
+ // user didn't complete oauth
213
+ if ((_a = providersWaitingOauthMessages.current) === null || _a === void 0 ? void 0 : _a[provider]) {
214
+ clearListeners();
215
+ handleError(`Linking ${provider} account window timeout.`);
216
+ }
217
+ setIsProcessing(false);
218
+ clearInterval(authWindowInterval.current);
219
+ }, sessionTimeout);
220
+ }
116
221
  });
117
222
  const unlinkSocialAccount = (provider) => __awaiter(void 0, void 0, void 0, function* () {
118
- var _e;
223
+ var _d;
119
224
  setError(undefined);
120
225
  setIsProcessing(true);
121
226
  if (!checkValidProvider(provider)) {
@@ -129,7 +234,7 @@ const useSocialAccounts = () => {
129
234
  try {
130
235
  const jwt = yield unlinkOAuth({
131
236
  environmentId,
132
- verifiedCrentialId: (_e = verifiedCredential.id) !== null && _e !== void 0 ? _e : '',
237
+ verifiedCrentialId: (_d = verifiedCredential.id) !== null && _d !== void 0 ? _d : '',
133
238
  }, String(userJwt));
134
239
  if (!jwt) {
135
240
  handleError(`Failed to unlink social account: ${provider} | ${verifiedCredential.id}`);
@@ -5,11 +5,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var _tslib = require('../../../../_virtual/_tslib.cjs');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var iconic = require('@dynamic-labs/iconic');
8
+ var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
8
9
  require('react');
9
10
  var Typography = require('../../components/Typography/Typography.cjs');
10
11
  require('@dynamic-labs/sdk-api');
11
12
  require('../../shared/logger.cjs');
12
- require('@dynamic-labs/wallet-connector-core');
13
13
  var ViewContext = require('../../context/ViewContext/ViewContext.cjs');
14
14
  require('@dynamic-labs/wallet-book');
15
15
  require('@dynamic-labs/utils');
@@ -47,7 +47,7 @@ require('../../components/MenuList/Dropdown/Dropdown.cjs');
47
47
  var Captcha = require('../../components/Captcha/Captcha.cjs');
48
48
 
49
49
  const CaptchaVerifyUser = () => {
50
- const { consumeNonce, displaySiweStatement, environmentId, projectSettings, setIsSingleWalletAccount, selectedWalletConnector: walletConnector, } = useInternalDynamicContext.useInternalDynamicContext();
50
+ const { consumeNonce, displaySiweStatement, environmentId, projectSettings, setIsSingleWalletAccount, selectedWalletConnector: walletConnector, walletUiUtils, } = useInternalDynamicContext.useInternalDynamicContext();
51
51
  const { setView } = ViewContext.useViewContext();
52
52
  const { setCaptchaToken } = CaptchaContext.useCaptchaContext();
53
53
  const verifyWallet = useVerifyWallet.useVerifyWallet({
@@ -65,7 +65,13 @@ const CaptchaVerifyUser = () => {
65
65
  if (!publicWalletAddress) {
66
66
  return;
67
67
  }
68
- setView('pending-signature');
68
+ if (!walletConnectorCore.isEmbeddedConnector(walletConnector) ||
69
+ walletConnectorCore.isBloctoConnector(walletConnector)) {
70
+ setView('pending-signature');
71
+ }
72
+ else {
73
+ walletUiUtils.disabledConfirmationOnce();
74
+ }
69
75
  if (requiresTwoStepAuthentication.requiresTwoStepAuthentication(walletConnector)) {
70
76
  setCaptchaToken(captchaToken);
71
77
  return;
@@ -1,11 +1,11 @@
1
1
  import { __awaiter } from '../../../../_virtual/_tslib.js';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { CaptchaWaveIcon } from '@dynamic-labs/iconic';
4
+ import { isEmbeddedConnector, isBloctoConnector } from '@dynamic-labs/wallet-connector-core';
4
5
  import 'react';
5
6
  import { Typography } from '../../components/Typography/Typography.js';
6
7
  import '@dynamic-labs/sdk-api';
7
8
  import '../../shared/logger.js';
8
- import '@dynamic-labs/wallet-connector-core';
9
9
  import { useViewContext } from '../../context/ViewContext/ViewContext.js';
10
10
  import '@dynamic-labs/wallet-book';
11
11
  import '@dynamic-labs/utils';
@@ -43,7 +43,7 @@ import '../../components/MenuList/Dropdown/Dropdown.js';
43
43
  import { Captcha } from '../../components/Captcha/Captcha.js';
44
44
 
45
45
  const CaptchaVerifyUser = () => {
46
- const { consumeNonce, displaySiweStatement, environmentId, projectSettings, setIsSingleWalletAccount, selectedWalletConnector: walletConnector, } = useInternalDynamicContext();
46
+ const { consumeNonce, displaySiweStatement, environmentId, projectSettings, setIsSingleWalletAccount, selectedWalletConnector: walletConnector, walletUiUtils, } = useInternalDynamicContext();
47
47
  const { setView } = useViewContext();
48
48
  const { setCaptchaToken } = useCaptchaContext();
49
49
  const verifyWallet = useVerifyWallet({
@@ -61,7 +61,13 @@ const CaptchaVerifyUser = () => {
61
61
  if (!publicWalletAddress) {
62
62
  return;
63
63
  }
64
- setView('pending-signature');
64
+ if (!isEmbeddedConnector(walletConnector) ||
65
+ isBloctoConnector(walletConnector)) {
66
+ setView('pending-signature');
67
+ }
68
+ else {
69
+ walletUiUtils.disabledConfirmationOnce();
70
+ }
65
71
  if (requiresTwoStepAuthentication(walletConnector)) {
66
72
  setCaptchaToken(captchaToken);
67
73
  return;
@@ -65,7 +65,7 @@ const EmailWalletOTPVerificationView = () => {
65
65
  const { data: isValid, isLoading, mutate: onSubmit, } = useMutation.useMutation((otp) => emailWalletConnector.verifyOneTimePassword(otp), {
66
66
  onFailure: (error) => setError(error),
67
67
  });
68
- return (jsxRuntime.jsx(OTPVerificationView.OTPVerificationView, { email: email, error: error, onClickBack: handleBackClick, isLoading: isLoading, onPinComplete: onSubmit, isValid: isValid === true, onPinChange: () => setError(undefined), onClickClose: handleOnClickClose, onClickEditEmail: handleBackClick, displayPoweredByDynamic: true }));
68
+ return (jsxRuntime.jsx(OTPVerificationView.OTPVerificationView, { email: email, error: error, onClickBack: handleBackClick, isLoading: isLoading, onPinComplete: onSubmit, isValid: isValid === true, onPinChange: () => setError(undefined), onClickClose: handleOnClickClose, onClickEditEmail: handleBackClick, displayPoweredByDynamic: true, successBannerText: 'Sign in to access your email based wallet' }));
69
69
  };
70
70
 
71
71
  exports.EmailWalletOTPVerificationView = EmailWalletOTPVerificationView;
@@ -61,7 +61,7 @@ const EmailWalletOTPVerificationView = () => {
61
61
  const { data: isValid, isLoading, mutate: onSubmit, } = useMutation((otp) => emailWalletConnector.verifyOneTimePassword(otp), {
62
62
  onFailure: (error) => setError(error),
63
63
  });
64
- return (jsx(OTPVerificationView, { email: email, error: error, onClickBack: handleBackClick, isLoading: isLoading, onPinComplete: onSubmit, isValid: isValid === true, onPinChange: () => setError(undefined), onClickClose: handleOnClickClose, onClickEditEmail: handleBackClick, displayPoweredByDynamic: true }));
64
+ return (jsx(OTPVerificationView, { email: email, error: error, onClickBack: handleBackClick, isLoading: isLoading, onPinComplete: onSubmit, isValid: isValid === true, onPinChange: () => setError(undefined), onClickClose: handleOnClickClose, onClickEditEmail: handleBackClick, displayPoweredByDynamic: true, successBannerText: 'Sign in to access your email based wallet' }));
65
65
  };
66
66
 
67
67
  export { EmailWalletOTPVerificationView };
@@ -53,12 +53,13 @@ var SelectNetworkButton = require('../../components/SelectNetworkButton/SelectNe
53
53
  var useApplyWalletConnectorNetwork = require('../../utils/hooks/useApplyWalletConnectorNetwork/useApplyWalletConnectorNetwork.cjs');
54
54
 
55
55
  const NetworkNotSupported = () => {
56
- const { network, onboardingImageUrl, selectedWalletConnector: walletConnector, connectedWallets, primaryWallet, isFullyConnected, setShowAuthFlow, } = useInternalDynamicContext.useInternalDynamicContext();
56
+ const { network, onboardingImageUrl, selectedWalletConnector: walletConnector, connectedWallets, primaryWallet, isFullyConnected, setShowAuthFlow, walletsToConnectByChain, } = useInternalDynamicContext.useInternalDynamicContext();
57
57
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
58
58
  const { data: walletConnectorNetwork } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), { deps: [primaryWallet, walletConnector, connectedWallets] });
59
59
  const finishConnectAndSign = useConnectAndSign.useConnectAndSign({
60
60
  shouldCallCallback: false,
61
- shouldUpdateWallets: !isFullyConnected,
61
+ shouldUpdateWallets: !isFullyConnected ||
62
+ (isFullyConnected && Boolean(walletsToConnectByChain === null || walletsToConnectByChain === void 0 ? void 0 : walletsToConnectByChain.length)),
62
63
  });
63
64
  const [isNetworkPickerOpen, setIsNetworkPickerOpen] = React.useState(false);
64
65
  // Finishes auth flow when wallet switches to proper network
@@ -49,12 +49,13 @@ import { SelectNetworkButton } from '../../components/SelectNetworkButton/Select
49
49
  import { useApplyWalletConnectorNetwork } from '../../utils/hooks/useApplyWalletConnectorNetwork/useApplyWalletConnectorNetwork.js';
50
50
 
51
51
  const NetworkNotSupported = () => {
52
- const { network, onboardingImageUrl, selectedWalletConnector: walletConnector, connectedWallets, primaryWallet, isFullyConnected, setShowAuthFlow, } = useInternalDynamicContext();
52
+ const { network, onboardingImageUrl, selectedWalletConnector: walletConnector, connectedWallets, primaryWallet, isFullyConnected, setShowAuthFlow, walletsToConnectByChain, } = useInternalDynamicContext();
53
53
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
54
54
  const { data: walletConnectorNetwork } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), { deps: [primaryWallet, walletConnector, connectedWallets] });
55
55
  const finishConnectAndSign = useConnectAndSign({
56
56
  shouldCallCallback: false,
57
- shouldUpdateWallets: !isFullyConnected,
57
+ shouldUpdateWallets: !isFullyConnected ||
58
+ (isFullyConnected && Boolean(walletsToConnectByChain === null || walletsToConnectByChain === void 0 ? void 0 : walletsToConnectByChain.length)),
58
59
  });
59
60
  const [isNetworkPickerOpen, setIsNetworkPickerOpen] = useState(false);
60
61
  // Finishes auth flow when wallet switches to proper network
@@ -54,14 +54,15 @@ var useApplyWalletConnectorNetwork = require('../../utils/hooks/useApplyWalletCo
54
54
  // as the wallet does not support programmatic network change.
55
55
  const NetworkNotSupportedSwitchManual = () => {
56
56
  var _a, _b;
57
- const { user, selectedWalletConnector: walletConnector, connectedWallets, isFullyConnected, setShowAuthFlow, } = useInternalDynamicContext.useInternalDynamicContext();
57
+ const { user, selectedWalletConnector: walletConnector, connectedWallets, isFullyConnected, setShowAuthFlow, walletsToConnectByChain, } = useInternalDynamicContext.useInternalDynamicContext();
58
58
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
59
59
  const { data: walletConnectorNetwork } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), {
60
60
  deps: [walletConnector, connectedWallets],
61
61
  });
62
62
  const finishConnectAndSign = useConnectAndSign.useConnectAndSign({
63
63
  shouldCallCallback: false,
64
- shouldUpdateWallets: !isFullyConnected,
64
+ shouldUpdateWallets: !isFullyConnected ||
65
+ (isFullyConnected && Boolean(walletsToConnectByChain === null || walletsToConnectByChain === void 0 ? void 0 : walletsToConnectByChain.length)),
65
66
  });
66
67
  // Finishes auth flow when wallet switches to proper network
67
68
  React.useEffect(() => {
@@ -50,14 +50,15 @@ import { useApplyWalletConnectorNetwork } from '../../utils/hooks/useApplyWallet
50
50
  // as the wallet does not support programmatic network change.
51
51
  const NetworkNotSupportedSwitchManual = () => {
52
52
  var _a, _b;
53
- const { user, selectedWalletConnector: walletConnector, connectedWallets, isFullyConnected, setShowAuthFlow, } = useInternalDynamicContext();
53
+ const { user, selectedWalletConnector: walletConnector, connectedWallets, isFullyConnected, setShowAuthFlow, walletsToConnectByChain, } = useInternalDynamicContext();
54
54
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
55
55
  const { data: walletConnectorNetwork } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), {
56
56
  deps: [walletConnector, connectedWallets],
57
57
  });
58
58
  const finishConnectAndSign = useConnectAndSign({
59
59
  shouldCallCallback: false,
60
- shouldUpdateWallets: !isFullyConnected,
60
+ shouldUpdateWallets: !isFullyConnected ||
61
+ (isFullyConnected && Boolean(walletsToConnectByChain === null || walletsToConnectByChain === void 0 ? void 0 : walletsToConnectByChain.length)),
61
62
  });
62
63
  // Finishes auth flow when wallet switches to proper network
63
64
  useEffect(() => {