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 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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://secure-appkit-git-chore-tma-support-reown-com.vercel.app'
/*
* 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://secure-appkit-git-chore-tma-support-reown-com.vercel.app 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
55 changes: 54 additions & 1 deletion packages/appkit/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import type {
ConnectedWalletInfo,
RouterControllerState,
ChainAdapter,
SdkVersion
SdkVersion,
AccountControllerState
} from '@reown/appkit-core'
import {
AccountController,
Expand Down Expand Up @@ -84,6 +85,7 @@ export class AppKit {
this.initControllers(options)
this.initOrContinue()
this.version = options.sdkVersion
this.checkExistingConnection()
}

public static getInstance() {
Expand Down Expand Up @@ -585,4 +587,55 @@ 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) {
await authConnector.provider.connectSocial(resultUri)
await ConnectionController.connectExternal(authConnector, authConnector.chain)
SafeLocalStorage.removeItem(SafeLocalStorageKeys.SOCIAL_PROVIDER)
EventsController.sendEvent({
type: 'track',
event: 'SOCIAL_LOGIN_SUCCESS',
properties: { provider: socialProviderToConnect }
})
}
} catch (error) {
// 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
78 changes: 67 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 @@ -131,23 +135,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 +170,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
18 changes: 12 additions & 6 deletions packages/scaffold-ui/src/partials/w3m-social-login-list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { state } from 'lit/decorators.js'
import styles from './styles.js'
import type { SocialProvider } from '@reown/appkit-utils'
import { SocialProviderEnum } from '@reown/appkit-utils'
import { SafeLocalStorage, SafeLocalStorageKeys } from '@reown/appkit-common'

@customElement('w3m-social-login-list')
export class W3mSocialLoginList extends LitElement {
Expand Down Expand Up @@ -98,21 +99,26 @@ export class W3mSocialLoginList extends LitElement {
RouterController.push('ConnectingSocial')

const authConnector = ConnectorController.getAuthConnector()
this.popupWindow = CoreHelperUtil.returnOpenHref(
'',
'popupWindow',
'width=600,height=800,scrollbars=yes'
)
if (!CoreHelperUtil.isTelegram()) {
this.popupWindow = CoreHelperUtil.returnOpenHref(
'',
'popupWindow',
'width=600,height=800,scrollbars=yes'
)
}

try {
if (authConnector && socialProvider) {
const { uri } = await authConnector.provider.getSocialRedirectUri({
provider: socialProvider
})

if (this.popupWindow && uri) {
AccountController.setSocialWindow(this.popupWindow, ChainController.state.activeChain)
this.popupWindow.location.href = uri
} else if (CoreHelperUtil.isTelegram() && uri) {
SafeLocalStorage.setItem(SafeLocalStorageKeys.SOCIAL_PROVIDER, socialProvider)
const parsedUri = CoreHelperUtil.formatTelegramSocialLoginUrl(uri)
CoreHelperUtil.openHref(parsedUri, '_top')
} else {
this.popupWindow?.close()
throw new Error('Something went wrong')
Expand Down
20 changes: 12 additions & 8 deletions packages/scaffold-ui/src/partials/w3m-social-login-widget/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { state, property } from 'lit/decorators.js'
import styles from './styles.js'
import { ifDefined } from 'lit/directives/if-defined.js'
import { SocialProviderEnum } from '@reown/appkit-utils'
import { SafeLocalStorage, SafeLocalStorageKeys } from '@reown/appkit-common'

const MAX_TOP_VIEW = 2
const MAXIMUM_LENGTH = 6
Expand Down Expand Up @@ -195,23 +196,26 @@ export class W3mSocialLoginWidget extends LitElement {
}
} else {
RouterController.push('ConnectingSocial')

const authConnector = ConnectorController.getAuthConnector()
this.popupWindow = CoreHelperUtil.returnOpenHref(
'',
'popupWindow',
'width=600,height=800,scrollbars=yes'
)

if (!CoreHelperUtil.isTelegram()) {
this.popupWindow = CoreHelperUtil.returnOpenHref(
'',
'popupWindow',
'width=600,height=800,scrollbars=yes'
)
}
try {
if (authConnector && socialProvider) {
const { uri } = await authConnector.provider.getSocialRedirectUri({
provider: socialProvider
})

if (this.popupWindow && uri) {
AccountController.setSocialWindow(this.popupWindow, ChainController.state.activeChain)
this.popupWindow.location.href = uri
} else if (CoreHelperUtil.isTelegram() && uri) {
SafeLocalStorage.setItem(SafeLocalStorageKeys.SOCIAL_PROVIDER, socialProvider)
const parsedUri = CoreHelperUtil.formatTelegramSocialLoginUrl(uri)
CoreHelperUtil.openHref(parsedUri, '_top')
} else {
this.popupWindow?.close()
throw new Error('Something went wrong')
Expand Down
3 changes: 1 addition & 2 deletions packages/scaffold-ui/src/utils/ConstantsUtil.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export const ConstantsUtil = {
ACCOUNT_TABS: [{ label: 'Tokens' }, { label: 'NFTs' }, { label: 'Activity' }],
SECURE_SITE_ORIGIN:
process.env['NEXT_PUBLIC_SECURE_SITE_ORIGIN'] || 'https://secure.walletconnect.org',
SECURE_SITE_ORIGIN: 'https://secure-appkit-git-chore-tma-support-reown-com.vercel.app',
VIEW_DIRECTION: {
Next: 'next',
Prev: 'prev'
Expand Down
3 changes: 2 additions & 1 deletion packages/wallet/src/W3mFrameConstants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const SECURE_SITE_SDK =
process.env['NEXT_PUBLIC_SECURE_SITE_SDK_URL'] || 'https://secure.walletconnect.org/sdk'
'https://secure-appkit-git-chore-tma-support-reown-com.vercel.app/sdk'
// Process.env['NEXT_PUBLIC_SECURE_SITE_SDK_URL'] || 'https://secure.walletconnect.org/sdk'

export const DEFAULT_LOG_LEVEL = process.env['NEXT_PUBLIC_DEFAULT_LOG_LEVEL'] || 'error'

Expand Down
Loading