Merge pull request #77 from zeriontech/feature/better-ios-redirect

Better iOS redirect
This commit is contained in:
Ivan Grachev 2022-08-29 19:59:48 +03:00 committed by GitHub
commit 06bee992c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 169 additions and 8 deletions

View File

@ -25,7 +25,7 @@ struct ExtensionBridge {
static func hasRequest(id: Int) -> Bool {
if initiatedRequests.contains(id) {
initiatedRequests.remove(id)
removeRequest(id: id)
return true
} else {
return false
@ -36,6 +36,10 @@ struct ExtensionBridge {
defaults?.set(response.json, forKey: key(id: response.id))
}
static func removeRequest(id: Int) {
initiatedRequests.remove(id)
}
static func removeResponse(id: Int) {
let key = key(id: id)
defaults?.removeObject(forKey: key)

View File

@ -7,6 +7,6 @@ struct InternalSafariRequest: Codable {
let subject: Subject
enum Subject: String, Codable {
case getResponse, didCompleteRequest
case getResponse, didCompleteRequest, cancelRequest
}
}

View File

@ -69,6 +69,7 @@ struct ResponseToExtension {
if let error = error {
json["error"] = error
json["provider"] = request.provider.rawValue
}
let bodyJSON = body?.json ?? [:]

View File

@ -10,6 +10,8 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
});
} else if (request.subject === "getLatestConfiguration") {
getLatestConfiguration(request.host, sendResponse);
} else if (request.subject === "cancelRequest") {
browser.runtime.sendNativeMessage("mac.tokenary.io", request);
}
return true;
});

View File

@ -15,6 +15,59 @@ function injectScript() {
scriptTag.textContent = request.responseText;
container.insertBefore(scriptTag, container.children[0]);
container.removeChild(scriptTag);
const styles = `
#tokenary-button {
font-family: "Helvetica";
font-size: min(6vw, 6vh);
font-weight: bold;
color: white;
background-color: #0093FF;
width: min(78vw, 78vh);
height: min(34vw, 34vh);
border: none;
border-radius: min(17vw, 17vh);
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
padding: 0px;
line-height: 1.2em;
}
@keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#tokenary-overlay {
position: fixed;
display: none;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0);
-webkit-backdrop-filter: blur(3pt);
z-index: 2147483647;
cursor: pointer;
align-content: center;
justify-content: center;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease;
animation-duration: 0.2s;
}
`;
const styleSheet = document.createElement("style");
styleSheet.innerText = styles;
container.insertBefore(styleSheet, container.children[0]);
} catch (error) {
console.error('Tokenary: Provider injection failed.', error);
}
@ -121,8 +174,14 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
// Receive from inpage
window.addEventListener("message", function(event) {
if (event.source == window && event.data && event.data.direction == "from-page-script") {
sendMessageToNativeApp(event.data.message);
if (event.source == window && event.data) {
if (event.data.direction == "from-page-script") {
sendMessageToNativeApp(event.data.message);
} else if (event.data.subject == "cancelRequest") {
const cancelRequest = event.data;
document.pendingRequestsIds.delete(cancelRequest.id);
browser.runtime.sendMessage(cancelRequest);
}
}
});

File diff suppressed because one or more lines are too long

View File

@ -30,6 +30,8 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
#endif
case .didCompleteRequest:
ExtensionBridge.removeResponse(id: id)
case .cancelRequest:
ExtensionBridge.removeRequest(id: id)
}
} else if let query = String(data: data, encoding: .utf8)?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let request = SafariRequest(query: query),

View File

@ -40,7 +40,11 @@ window.addEventListener("message", function(event) {
const response = event.data.response;
const id = event.data.id;
if ("latestConfigurations" in response) {
if ("overlayConfiguration" in response) {
window.tokenary.overlayConfiguration = response.overlayConfiguration;
// TODO: use queue or map instead;
window.tokenary.showOverlay();
} else if ("latestConfigurations" in response) {
const name = "didLoadLatestConfiguration";
var remainingProviders = new Set(["ethereum", "solana", "near"]);
@ -101,3 +105,59 @@ function deliverResponseToSpecificProvider(id, response, provider) {
window.near.processTokenaryResponse(id, response);
}
}
// MARK: - Tokenary overlay for iOS
window.tokenary.overlayTapped = () => {
window.tokenary.hideOverlayImmediately(true);
const request = window.tokenary.overlayConfiguration.request;
deliverResponseToSpecificProvider(request.id, {id: request.id, error: "Canceled", name: request.name}, request.provider);
const cancelRequest = {subject: "cancelRequest", id: request.id};
window.postMessage(cancelRequest, "*");
};
window.tokenary.hideOverlayImmediately = (immediately) => {
if (immediately) {
document.getElementById("tokenary-overlay").style.display = "none";
} else {
setTimeout( function() { window.tokenary.hideOverlayImmediately(true); }, 200);
}
};
window.tokenary.showOverlay = () => {
const overlay = document.getElementById("tokenary-overlay");
if (overlay) {
window.tokenary.unhideOverlay(overlay);
} else {
window.tokenary.createOverlay();
}
};
window.tokenary.createOverlay = () => {
const overlay = document.createElement("div");
overlay.setAttribute("id", "tokenary-overlay");
overlay.setAttribute("ontouchstart", `
event.stopPropagation();
if (event.target === event.currentTarget) {
window.tokenary.overlayTapped();
return false;
}
`);
overlay.innerHTML = `<button id="tokenary-button" onclick="window.tokenary.overlayButtonTapped();">Proceed in Tokenary</button>`;
document.body.appendChild(overlay);
window.tokenary.unhideOverlay(overlay);
};
window.tokenary.unhideOverlay = (overlay) => {
overlay.firstChild.innerHTML = window.tokenary.overlayConfiguration.title;
overlay.style.display = "grid";
}
window.tokenary.overlayButtonTapped = () => {
const request = window.tokenary.overlayConfiguration.request;
window.location.href = "https://tokenary.io/extension?query=" + encodeURIComponent(JSON.stringify(request));
window.tokenary.hideOverlayImmediately(false);
};

View File

@ -17,6 +17,35 @@ function platformSpecificProcessMessage(message) {
if (message.provider == "ethereum" && (message.name == "switchEthereumChain" || message.name == "addEthereumChain")) {
return;
} else {
window.location.href = "tokenary://" + encodeURIComponent(JSON.stringify(message));
var title = "Proceed<br>in Tokenary";
switch (message.name) {
case "signPersonalMessage":
case "signMessage":
case "signTypedMessage":
title = "Sign Message<br>in Tokenary";
break;
case "signTransaction":
case "signAndSendTransactions":
case "signAllTransactions":
case "signAndSendTransaction":
title = "Approve Transaction<br>in Tokenary";
break;
case "requestAccounts":
case "signIn":
case "connect":
title = "Connect<br>Tokenary";
break;
case "switchAccount":
const latestConfigurations = message.body.latestConfigurations;
if (Array.isArray(latestConfigurations) && latestConfigurations.length) {
title = "Switch<br>Account";
} else {
title = "Connect<br>Tokenary";
}
break;
}
const response = {overlayConfiguration: {request: message, title: title}};
window.postMessage({direction: "from-content-script", response: response, id: message.id}, "*");
}
}

View File

@ -212,7 +212,7 @@ class AccountsListViewController: UIViewController, DataStateContainer {
}
@objc private func processInput() {
let prefix = "tokenary://"
let prefix = "https://tokenary.io/extension?query="
guard let url = launchURL?.absoluteString, url.hasPrefix(prefix),
let request = SafariRequest(query: String(url.dropFirst(prefix.count))) else { return }
launchURL = nil

View File

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:tokenary.io</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.io.tokenary</string>