Skip to content

Commit

Permalink
PKG -- [fcl] Add VIEW/DEEPLINK (#1763)
Browse files Browse the repository at this point in the history
  • Loading branch information
jribbink authored Aug 31, 2023
1 parent 1475232 commit 3c99c85
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 37 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-bananas-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/fcl": minor
---

Add VIEW/DEEPLINK
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {normalizePollingResponse} from "../../../../normalizers/service/polling-response"
import {serviceEndpoint} from "./service-endpoint"
import {invariant} from "@onflow/util-invariant"
import {fetchService} from "./fetch-service"

Expand Down
8 changes: 6 additions & 2 deletions packages/fcl/src/utils/react-native/exec-local.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import {renderBrowser} from "./render-browser"
import {renderDeeplink} from "./render-deeplink"

const NOT_IMPLEMENTED = (strategy) => () => {
throw new Error(`${strategy} Strategy util has not been implemented on this platform`)
const NOT_IMPLEMENTED = strategy => () => {
throw new Error(
`${strategy} Strategy util has not been implemented on this platform`
)
}

const VIEWS = {
"VIEW/IFRAME": NOT_IMPLEMENTED("VIEW/IFRAME"),
"VIEW/POP": NOT_IMPLEMENTED("VIEW/IFRAME"),
"VIEW/TAB": NOT_IMPLEMENTED("VIEW/TAB"),
"VIEW/MOBILE_BROWSER": renderBrowser,
"VIEW/DEEPLINK": renderDeeplink,
}

export async function execLocal(
Expand Down
26 changes: 15 additions & 11 deletions packages/fcl/src/utils/react-native/render-browser.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import * as WebBrowser from "expo-web-browser"
import * as Linking from 'expo-linking'
import { FCL_REDIRECT_URL_PARAM_NAME } from "../constants"
import * as Linking from "expo-linking"
import {FCL_REDIRECT_URL_PARAM_NAME} from "../constants"
import {URL} from "../url"

/**
*
* @param {URL} src
* @param {object} opts
*
* @param {URL} src
* @param {object} opts
* @returns {[object, () => void]}
*/
export function renderBrowser(src, opts = {}) {
const redirectUrl = Linking.createURL("$$fcl_auth_callback$$", {queryParams: {}})
src.searchParams.append(FCL_REDIRECT_URL_PARAM_NAME, redirectUrl)
const webbrowser = WebBrowser.openAuthSessionAsync(src.toString())
const redirectUrl = Linking.createURL("$$fcl_auth_callback$$", {
queryParams: {},
})
const url = new URL(src.toString())
url.searchParams.append(FCL_REDIRECT_URL_PARAM_NAME, redirectUrl)
const webbrowser = WebBrowser.openAuthSessionAsync(url.toString())

const unmount = () => {
try {
Expand All @@ -21,10 +25,10 @@ export function renderBrowser(src, opts = {}) {
}
}

// Call onClose when the webbrowser is closed
// Call onClose when the webbrowser is closed
webbrowser.then(() => {
if(opts?.onClose) {
opts.onClose()
if (opts?.onClose) {
opts.onClose()
}
})

Expand Down
49 changes: 49 additions & 0 deletions packages/fcl/src/utils/react-native/render-deeplink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as Linking from "expo-linking"
import {AppState} from "react-native"
import {URL} from "../url"

/**
* Renders a deeplink view (i.e. deep links to a wallet app)
*
* @param {URL} src
* @param {object} opts
* @param {() => void} [opts.onClose]
* @returns {[null, () => void]}
*/
export function renderDeeplink(src, opts = {}) {
const url = new URL(src.toString())

// Custom schemes (i.e mywallet://) are not supported for
// security reasons. These schemes can be hijacked by malicious
// apps and impersonate the wallet.
//
// Wallet developers should register a universal link instead.
// (i.e https://mywallet.com/ or https://link.mywallet.com/)
//
// Additionally this allows the wallet to redirect to the app
// store/show custom web content if the wallet is not installed.
if (url.protocol !== "https:") {
throw new Error(
"Deeplink must be https scheme. Custom schemes are not supported, please use a universal link/app link instead."
)
}

// Link to the target url
Linking.openURL(url.toString())

const onClose = opts.onClose || (() => {})

const onAppStateChange = state => {
if (state === "active") {
unmount()
onClose()
}
}
AppState.addEventListener("change", onAppStateChange)

const unmount = () => {
AppState.removeEventListener("change", onAppStateChange)
}

return [null, unmount]
}
20 changes: 11 additions & 9 deletions packages/fcl/src/utils/react-native/strategies/utils/browser.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import * as Linking from 'expo-linking'
import * as Linking from "expo-linking"
import {renderBrowser} from "../../render-browser"
import { serviceEndpoint } from "./service-endpoint"
import { buildMessageHandler } from "../../../../current-user/exec-service/strategies/utils/buildMessageHandler"
import { FCL_RESPONSE_PARAM_NAME } from '../../../constants'
import {serviceEndpoint} from "./service-endpoint"
import {buildMessageHandler} from "../../../../current-user/exec-service/strategies/utils/buildMessageHandler"
import {FCL_RESPONSE_PARAM_NAME} from "../../../constants"

const noop = () => {}

export function browser(service, config, body, opts = {}) {
if (service == null) return {send: noop, close: noop}

const onClose = opts.onClose || noop
const onMessage = noop
const onReady = noop
Expand All @@ -22,14 +22,16 @@ export function browser(service, config, body, opts = {}) {
onMessage,
})
const parseDeeplink = ({url}) => {
const { queryParams } = Linking.parse(url)
const {queryParams} = Linking.parse(url)
const eventDataRaw = queryParams[FCL_RESPONSE_PARAM_NAME]
const eventData = JSON.parse(eventDataRaw)

handler({data: eventData})
}

const [browser, unmount] = renderBrowser(serviceEndpoint(service, config, body))

const [browser, unmount] = renderBrowser(
serviceEndpoint(service, config, body)
)
// Android deeplink parsing
Linking.addEventListener("url", parseDeeplink)
// iOS deeplink parsing
Expand Down
3 changes: 2 additions & 1 deletion packages/fcl/src/utils/web/exec-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ const VIEWS = {
"VIEW/POP": renderPop,
"VIEW/TAB": renderTab,
"VIEW/MOBILE_BROWSER": NOT_IMPLEMENTED,
"VIEW/DEEPLINK": NOT_IMPLEMENTED,
}

export async function execLocal(service, opts = {serviceEndpoint: () => {}}) {
const { serviceEndpoint } = opts
const {serviceEndpoint} = opts
try {
return VIEWS[service.method](serviceEndpoint(service), opts)
} catch (error) {
Expand Down
27 changes: 14 additions & 13 deletions packages/fcl/src/wallet-utils/send-msg-to-fcl.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import {FCL_REDIRECT_URL_PARAM_NAME, FCL_RESPONSE_PARAM_NAME} from "../utils/constants"
import {
FCL_REDIRECT_URL_PARAM_NAME,
FCL_RESPONSE_PARAM_NAME,
} from "../utils/constants"
import {onMessageFromFCL} from "./on-message-from-fcl"
import {URL} from "../utils/url"

/**
* @description
* Sends message to FCL window
*
*
* @param {string} type - Message type
* @param {object} msg - Message object
* @returns {void}
*
*
* @example
* sendMsgToFCL("FCL:VIEW:RESPONSE", {
* f_type: "PollingResponse",
Expand All @@ -23,12 +27,9 @@ export const sendMsgToFCL = (type, msg = {}) => {

const urlParams = new URLSearchParams(window.location.search)
const redirectUrl = urlParams.get(FCL_REDIRECT_URL_PARAM_NAME)
if(redirectUrl) {
if (redirectUrl) {
const url = new URL(redirectUrl)
url.searchParams.append(
FCL_RESPONSE_PARAM_NAME,
JSON.stringify(data)
)
url.searchParams.append(FCL_RESPONSE_PARAM_NAME, JSON.stringify(data))
window.location.href = url.href
} else if (window.location !== window.parent.location) {
window.parent.postMessage({...msg, type}, "*")
Expand All @@ -42,7 +43,7 @@ export const sendMsgToFCL = (type, msg = {}) => {
/**
* @description
* Listens for "FCL:VIEW:READY:RESPONSE" and sends "FCL:VIEW:READY"
*
*
* @param {Function} cb - Callback function
* @param {object} msg - Message object
* @returns {void}
Expand All @@ -55,7 +56,7 @@ export const ready = (cb, msg = {}) => {
/**
* @description
* Sends "FCL:VIEW:CLOSE"
*
*
* @returns {void}
*/
export const close = () => {
Expand All @@ -65,7 +66,7 @@ export const close = () => {
/**
* @description
* Sends "FCL:VIEW:RESPONSE" with status "APPROVED"
*
*
* @param {object} data - Data object
* @returns {void}
*/
Expand All @@ -82,7 +83,7 @@ export const approve = data => {
/**
* @description
* Sends "FCL:VIEW:RESPONSE" with status "DECLINED"
*
*
* @param {string} reason - Reason for declining
* @returns {void}
*/
Expand All @@ -99,7 +100,7 @@ export const decline = reason => {
/**
* @description
* Sends "FCL:VIEW:RESPONSE" with status "REDIRECT"
*
*
* @param {object} data - Data object
* @returns {void}
*/
Expand Down

0 comments on commit 3c99c85

Please sign in to comment.