Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/tma socials #3025

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6cdbf43
feat: tma socials
ganchoradkov Oct 7, 2024
5ae9a52
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 7, 2024
3e1651e
chore: secure site domain in lab
ganchoradkov Oct 7, 2024
8e5417f
chore: frame src
ganchoradkov Oct 7, 2024
5cba17f
chore: uses `--`
ganchoradkov Oct 7, 2024
fcb9e72
fix: popup
ganchoradkov Oct 7, 2024
476fd2b
refactor: url target
ganchoradkov Oct 7, 2024
4d20939
chore: adds `_top`
ganchoradkov Oct 7, 2024
e302cfe
chore: rm frame-ancestors
ganchoradkov Oct 7, 2024
0446b0b
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 9, 2024
bfa921a
chore: cleanup logs
ganchoradkov Oct 9, 2024
80e4350
Merge branch 'feat/tma-socials' of github.com:WalletConnect/web3modal…
ganchoradkov Oct 9, 2024
b16a068
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 9, 2024
8737cd1
fix: params
ganchoradkov Oct 9, 2024
cffa36a
Merge branch 'feat/tma-socials' of github.com:WalletConnect/web3modal…
ganchoradkov Oct 9, 2024
893c68e
fix: loading state and wagmi social connnections
ganchoradkov Oct 10, 2024
3508cf4
chore: rm redundant test check
ganchoradkov Oct 10, 2024
ebf1ac1
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 10, 2024
94d36d5
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 17, 2024
87f5bbb
fix: connected socials label
ganchoradkov Oct 17, 2024
6f3afcc
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 17, 2024
4a6ac1a
feat: hides non working social per platform
ganchoradkov Oct 18, 2024
f7d2fea
Merge branch 'feat/tma-socials' of github.com:WalletConnect/web3modal…
ganchoradkov Oct 18, 2024
1bdc8a7
fix: rm unused import
ganchoradkov Oct 18, 2024
b0ad24e
Merge branch 'main' into feat/tma-socials
ganchoradkov Oct 30, 2024
470dde0
chore: updates secure url
ganchoradkov Oct 30, 2024
6871f2f
chore: adds logs
ganchoradkov Oct 30, 2024
b26ce38
chore: more logs
ganchoradkov Oct 30, 2024
addbbc6
fix: ethers merge conflict
ganchoradkov Oct 30, 2024
3cbf2e0
chore: rm logs
ganchoradkov Oct 30, 2024
fafda44
Merge branch 'main' into feat/tma-socials
ganchoradkov Nov 6, 2024
0fbd996
feat: adds loader on iphone while pairing uri is generated in tma con…
ganchoradkov Nov 6, 2024
4fc87d6
feat: adds loader to recommended wallets as well in tma context
ganchoradkov Nov 6, 2024
6623115
refactor: removes disabled prop while loading and instead blocks rout…
ganchoradkov Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions apps/laboratory/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ const SHAKRA_UI = `'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE='`
* DO NOT use `unsafe-inline` or `unsafe-eval` for `script-src` or `default-src` in production as this
* is against CSP best practices
*/
const secureSiteDomain = process.env.NEXT_PUBLIC_SECURE_SITE_SDK_URL
? new URL(process.env.NEXT_PUBLIC_SECURE_SITE_SDK_URL).origin
: ''
const secureSiteDomain = 'https://b1a9fa46.secure-appkit-sdk.pages.dev'
/*
* Process.env.NEXT_PUBLIC_SECURE_SITE_SDK_URL
* ? new URL(process.env.NEXT_PUBLIC_SECURE_SITE_SDK_URL).origin
* : ''
*/
const cspHeader = `
default-src 'self';
script-src 'self' ${SHAKRA_UI} ${process.env.NODE_ENV === 'production' ? '' : "'unsafe-eval'"};
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src * 'self' data: blob: https://walletconnect.org https://walletconnect.com https://secure.walletconnect.com https://secure.walletconnect.org https://tokens-data.1inch.io https://tokens.1inch.io https://ipfs.io https://appkit-lab.reown.org;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://react-wallet.walletconnect.com https://rpc.walletconnect.com https://rpc.walletconnect.org https://relay.walletconnect.com https://relay.walletconnect.org wss://relay.walletconnect.com wss://relay.walletconnect.org https://pulse.walletconnect.com https://pulse.walletconnect.org https://api.web3modal.com https://api.web3modal.org wss://www.walletlink.org https://o1095249.ingest.sentry.io https://quote-api.jup.ag;
frame-src 'self' https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org https://secure.reown.com https://widget.solflare.com/ ${secureSiteDomain}/;
frame-src 'self' https://b1a9fa46.secure-appkit-sdk.pages.dev https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org https://secure.reown.com https://widget.solflare.com/ ${secureSiteDomain}/;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
report-uri https://o1095249.ingest.sentry.io/api/4505685639364608/security/?sentry_key=36ff1e79c60877fce6c0273e94a8ed69;
report-to csp-endpoint
`
Expand Down
17 changes: 9 additions & 8 deletions packages/adapters/ethers/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1173,16 +1173,17 @@ export class EthersAdapter {
chain: this.chainNamespace
})

this.appKit?.setLoading(true)
const isLoginEmailUsed = this.authProvider.getLoginEmailUsed()
this.appKit?.setLoading(isLoginEmailUsed)

if (isLoginEmailUsed) {
const { isConnected } = await this.authProvider.isConnected()
if (isConnected) {
await this.setAuthProvider()
} else {
this.appKit?.setLoading(false)
}
this.appKit?.setLoading(isLoginEmailUsed)
}

const { isConnected } = await this.authProvider.isConnected()
if (isConnected) {
await this.setAuthProvider()
} else if (isLoginEmailUsed) {
this.appKit?.setLoading(false)
}
}
}
Expand Down
1 change: 0 additions & 1 deletion packages/adapters/ethers/src/tests/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,6 @@ describe('EthersAdapter', () => {
provider: expect.any(Object),
chain: 'eip155'
})
expect(mockAppKit.setLoading).toHaveBeenCalledWith(false)
})

describe('Auth Connector Handle Requests', () => {
Expand Down
8 changes: 7 additions & 1 deletion packages/adapters/wagmi/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -636,10 +636,10 @@ export class WagmiAdapter implements ChainAdapter {
caipNetworks: this.caipNetworks
})

this.syncConnectors(this.wagmiConfig.connectors)
this.syncAuthConnector(
this.wagmiConfig?.connectors.find(c => c.id === ConstantsUtil.AUTH_CONNECTOR_ID)
)
this.syncConnectors(this.wagmiConfig.connectors)
this.syncRequestedNetworks(this.caipNetworks)

watchConnectors(this.wagmiConfig, {
Expand Down Expand Up @@ -992,6 +992,12 @@ export class WagmiAdapter implements ChainAdapter {
if (bypassWindowCheck || (typeof window !== 'undefined' && connector)) {
const provider = (await connector.getProvider()) as W3mFrameProvider

const isLoginEmailUsed = provider.getLoginEmailUsed()

if (isLoginEmailUsed) {
this.appKit?.setLoading(isLoginEmailUsed)
}

provider.onRpcRequest((request: W3mFrameTypes.RPCRequest) => {
if (W3mFrameHelpers.checkIfRequestExists(request)) {
if (!W3mFrameHelpers.checkIfRequestIsSafe(request)) {
Expand Down
62 changes: 61 additions & 1 deletion packages/appkit/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
RouterControllerState,
ChainAdapter,
SdkVersion,
AccountControllerState,
UseAppKitAccountReturn,
UseAppKitNetworkReturn
} from '@reown/appkit-core'
Expand All @@ -27,7 +28,8 @@ import {
OptionsController,
AssetUtil,
ApiController,
AlertController
AlertController,
StorageUtil
} from '@reown/appkit-core'
import { setColorTheme, setThemeVariables } from '@reown/appkit-ui'
import {
Expand Down Expand Up @@ -87,6 +89,10 @@ export class AppKit {
this.initControllers(options)
this.initOrContinue()
this.version = options.sdkVersion
// Check on the next thick because wagmiAdapter authConnector is not immediately available
setTimeout(() => {
this.checkExistingConnection()
}, 0)
}

public static getInstance() {
Expand Down Expand Up @@ -629,4 +635,58 @@ export class AppKit {

return this.initPromise
}

private async checkExistingConnection() {
try {
if (!CoreHelperUtil.isTelegram()) {
return
}
const socialProviderToConnect = SafeLocalStorage.getItem(
SafeLocalStorageKeys.SOCIAL_PROVIDER
) as AccountControllerState['socialProvider']
if (!socialProviderToConnect) {
return
}
if (typeof window === 'undefined' || typeof document === 'undefined') {
return
}
const url = new URL(window.location.href)
const resultUri = url.searchParams.get('result_uri')
if (!resultUri) {
return
}
AccountController.setSocialProvider(
socialProviderToConnect,
ChainController.state.activeChain
)
const authConnector = ConnectorController.getAuthConnector()
if (socialProviderToConnect && authConnector) {
this.setLoading(true)
await authConnector.provider.connectSocial(resultUri)
await ConnectionController.connectExternal(authConnector, authConnector.chain)
StorageUtil.setConnectedSocialProvider(socialProviderToConnect)
SafeLocalStorage.removeItem(SafeLocalStorageKeys.SOCIAL_PROVIDER)
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_SUCCESS',
properties: { provider: socialProviderToConnect }
})
}
} catch (error) {
this.setLoading(false)
// eslint-disable-next-line no-console
console.error('checkExistingConnection error', error)
}

try {
const url = new URL(window.location.href)
// Remove the 'result_uri' parameter
url.searchParams.delete('result_uri')
// Update the URL without reloading the page
window.history.replaceState({}, document.title, url.toString())
} catch (error) {
// eslint-disable-next-line no-console
console.error(error)
}
}
}
4 changes: 3 additions & 1 deletion packages/common/src/utils/SafeLocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type SafeLocalStorageItems = {
'@appkit/connected_social': string
'@appkit/connected_social_username': string
'@appkit/recent_wallets': string
'@appkit/social_provider': string
/*
* DO NOT CHANGE: @walletconnect/universal-provider requires us to set this specific key
* This value is a stringified version of { href: stiring; name: string }
Expand All @@ -25,7 +26,8 @@ export const SafeLocalStorageKeys = {
CONNECTED_SOCIAL: '@appkit/connected_social',
CONNECTED_SOCIAL_USERNAME: '@appkit/connected_social_username',
RECENT_WALLETS: '@appkit/recent_wallets',
DEEPLINK_CHOICE: 'WALLETCONNECT_DEEPLINK_CHOICE'
DEEPLINK_CHOICE: 'WALLETCONNECT_DEEPLINK_CHOICE',
SOCIAL_PROVIDER: '@appkit/social_provider'
} as const

export const SafeLocalStorage = {
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/controllers/OptionsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
Tokens
} from '../utils/TypeUtil.js'
import { ConstantsUtil } from '../utils/ConstantsUtil.js'
import { filterSocialsByPlatform } from '../utils/OptionsUtil.js'
import type { SIWXConfig } from '../utils/SIWXUtil.js'

// -- Types --------------------------------------------- //
Expand Down Expand Up @@ -160,8 +161,13 @@ export const OptionsController = {
state.features = ConstantsUtil.DEFAULT_FEATURES
}

let filteredValue = value
if (key === 'socials') {
filteredValue = filterSocialsByPlatform(state.features.socials)
}

if (key in state.features) {
;(state.features as Record<keyof Features, unknown>)[key as keyof Features] = value
;(state.features as Record<keyof Features, unknown>)[key as keyof Features] = filteredValue
}
})
},
Expand Down
84 changes: 73 additions & 11 deletions packages/core/src/utils/CoreHelperUtil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { AppKitSdkVersion, Balance, ChainNamespace } from '@reown/appkit-common'
import { ConstantsUtil as CommonConstants } from '@reown/appkit-common'
import {
ConstantsUtil as CommonConstants,
SafeLocalStorage,
SafeLocalStorageKeys
} from '@reown/appkit-common'
import { ConstantsUtil } from './ConstantsUtil.js'
import type { CaipAddress, CaipNetwork } from '@reown/appkit-common'
import type { ChainAdapter, LinkingRecord } from './TypeUtil.js'
Expand Down Expand Up @@ -34,6 +38,12 @@ export const CoreHelperUtil = {
return CoreHelperUtil.isMobile() && (ua.includes('iphone') || ua.includes('ipad'))
},

isMac() {
const ua = window.navigator.userAgent.toLowerCase()

return ua.includes('macintosh') && !ua.includes('safari')
},

isClient() {
return typeof window !== 'undefined'
},
Expand Down Expand Up @@ -131,23 +141,30 @@ export const CoreHelperUtil = {
getOpenTargetForPlatform(target: string) {
// Only '_blank' deeplinks work in Telegram context
if (this.isTelegram()) {
// But for social login, we need to load the page in the same context
if (SafeLocalStorage.getItem(SafeLocalStorageKeys.SOCIAL_PROVIDER)) {
return '_top'
}

return '_blank'
}

return target
},
openHref(href: string, target: '_blank' | '_self' | 'popupWindow', features?: string) {
window.open(href, this.getOpenTargetForPlatform(target), features || 'noreferrer noopener')
openHref(
href: string,
target: '_top' | '_blank' | '_self' | 'popupWindow',
features = 'noreferrer noopener'
) {
window.open(href, this.getOpenTargetForPlatform(target), features)
},

returnOpenHref(href: string, target: '_blank' | '_self' | 'popupWindow', features?: string) {
return window.open(
href,
this.getOpenTargetForPlatform(target),
features || 'noreferrer noopener'
)
returnOpenHref(
href: string,
target: '_top' | '_blank' | '_self' | 'popupWindow',
features = 'noreferrer noopener'
) {
return window.open(href, this.getOpenTargetForPlatform(target), features)
},

isTelegram() {
return (
typeof window !== 'undefined' &&
Expand All @@ -159,6 +176,51 @@ export const CoreHelperUtil = {
Boolean((window as any).TelegramWebviewProxyProto))
)
},
formatTelegramSocialLoginUrl(url: string) {
const valueToInject = `--${encodeURIComponent(window.location.href)}`
const paramToInject = 'state='
const parsedUrl = new URL(url)
if (parsedUrl.host === 'auth.magic.link') {
const providerParam = 'provider_authorization_url='
const providerUrl = url.substring(url.indexOf(providerParam) + providerParam.length)
const resultUrl = this.injectIntoUrl(
decodeURIComponent(providerUrl),
paramToInject,
valueToInject
)

return url.replace(providerUrl, encodeURIComponent(resultUrl))
}

return this.injectIntoUrl(url, paramToInject, valueToInject)
},
injectIntoUrl(url: string, key: string, appendString: string) {
// Find the position of "key" e.g. "state=" in the URL
const keyIndex = url.indexOf(key)

if (keyIndex === -1) {
throw new Error(`${key} parameter not found in the URL: ${url}`)
}

// Find the position of the next "&" after "key"
const keyEndIndex = url.indexOf('&', keyIndex)
const keyLength = key.length
// If there is no "&" after key, it means "key" is the last parameter
// eslint-disable-next-line no-negated-condition
const keyParamEnd = keyEndIndex !== -1 ? keyEndIndex : url.length
// Extract the part of the URL before the key value
const beforeKeyValue = url.substring(0, keyIndex + keyLength)
// Extract the current key value
const currentKeyValue = url.substring(keyIndex + keyLength, keyParamEnd)
// Extract the part of the URL after the key value
const afterKeyValue = url.substring(keyEndIndex)
// Append the new string to the key value
const newKeyValue = currentKeyValue + appendString
// Reconstruct the URL with the appended key value
const newUrl = beforeKeyValue + newKeyValue + afterKeyValue

return newUrl
},

async preloadImage(src: string) {
const imagePromise = new Promise((resolve, reject) => {
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/utils/OptionsUtil.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ConstantsUtil } from './ConstantsUtil.js'
import { CoreHelperUtil } from './CoreHelperUtil.js'
import type { Features, FeaturesKeys } from './TypeUtil.js'

export const OptionsUtil = {
Expand All @@ -12,3 +13,23 @@ export const OptionsUtil = {
return optionValue as Features[typeof key]
}
}

export function filterSocialsByPlatform<T>(socials: Features['socials']) {
if (!socials || !socials.length) {
return socials as T
}

if (CoreHelperUtil.isTelegram()) {
if (CoreHelperUtil.isIos()) {
return socials.filter(s => s !== 'google')
}
if (CoreHelperUtil.isMac()) {
return socials.filter(s => s !== 'x')
}
if (CoreHelperUtil.isAndroid()) {
return socials.filter(s => !['facebook', 'x'].includes(s))
}
}

return socials
}
Loading
Loading