-
Notifications
You must be signed in to change notification settings - Fork 197
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1916 from AaronDewes/window-alby
feat: Add window.alby methods
- Loading branch information
Showing
15 changed files
with
377 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { act, render, screen } from "@testing-library/react"; | ||
import { MemoryRouter } from "react-router-dom"; | ||
import type { OriginData } from "~/types"; | ||
|
||
import ConfirmAddAccount from "./index"; | ||
|
||
const mockOrigin: OriginData = { | ||
location: "https://getalby.com/demo", | ||
domain: "https://getalby.com", | ||
host: "getalby.com", | ||
pathname: "/demo", | ||
name: "Alby", | ||
description: "", | ||
icon: "https://getalby.com/assets/alby-503261fa1b83c396b7ba8d927db7072d15fea5a84d387a654c5d0a2cefd44604.svg", | ||
metaData: { | ||
title: "Alby Demo", | ||
url: "https://getalby.com/demo", | ||
provider: "Alby", | ||
image: | ||
"https://getalby.com/assets/alby-503261fa1b83c396b7ba8d927db7072d15fea5a84d387a654c5d0a2cefd44604.svg", | ||
icon: "https://getalby.com/favicon.ico", | ||
}, | ||
external: true, | ||
}; | ||
|
||
jest.mock("~/app/hooks/useNavigationState", () => { | ||
return { | ||
useNavigationState: jest.fn(() => ({ | ||
origin: mockOrigin, | ||
args: { | ||
connector: "nativecitadel", | ||
name: "Your Citadel wallet", | ||
config: { connectionString: "..." }, | ||
}, | ||
})), | ||
}; | ||
}); | ||
|
||
describe("ConfirmAddAccount", () => { | ||
test("render", async () => { | ||
await act(async () => { | ||
render( | ||
<MemoryRouter> | ||
<ConfirmAddAccount /> | ||
</MemoryRouter> | ||
); | ||
}); | ||
|
||
expect( | ||
await screen.findByText( | ||
"This website wants to add an account (Citadel (over Tor)):" | ||
) | ||
).toBeInTheDocument(); | ||
expect(await screen.findByText("Your Citadel wallet")).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import ConfirmOrCancel from "@components/ConfirmOrCancel"; | ||
import Container from "@components/Container"; | ||
import ContentMessage from "@components/ContentMessage"; | ||
import PublisherCard from "@components/PublisherCard"; | ||
import { useState } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
import { toast } from "react-toastify"; | ||
import ScreenHeader from "~/app/components/ScreenHeader"; | ||
import { useNavigationState } from "~/app/hooks/useNavigationState"; | ||
import { USER_REJECTED_ERROR } from "~/common/constants"; | ||
import msg from "~/common/lib/msg"; | ||
import type { OriginData } from "~/types"; | ||
|
||
function ConfirmAddAccount() { | ||
const navState = useNavigationState(); | ||
const { t: tCommon } = useTranslation("common"); | ||
const { t } = useTranslation("translation", { | ||
keyPrefix: "confirm_add_account", | ||
}); | ||
|
||
const name = navState.args?.name as string; | ||
const connector = navState.args?.connector as string; | ||
const config = navState.args?.config as unknown; | ||
const origin = navState.origin as OriginData; | ||
const [loading, setLoading] = useState(false); | ||
|
||
async function confirm() { | ||
try { | ||
setLoading(true); | ||
const response = await msg.request( | ||
"addAccount", | ||
{ name, connector, config }, | ||
{ origin } | ||
); | ||
msg.reply(response); | ||
} catch (e) { | ||
console.error(e); | ||
if (e instanceof Error) toast.error(`${tCommon("error")}: ${e.message}`); | ||
} finally { | ||
setLoading(false); | ||
} | ||
} | ||
|
||
function reject(e: React.MouseEvent<HTMLAnchorElement>) { | ||
e.preventDefault(); | ||
msg.error(USER_REJECTED_ERROR); | ||
} | ||
|
||
return ( | ||
<div className="h-full flex flex-col overflow-y-auto no-scrollbar"> | ||
<ScreenHeader title={t("title")} /> | ||
<Container justifyBetween maxWidth="sm"> | ||
<div> | ||
<PublisherCard | ||
title={origin.name} | ||
image={origin.icon} | ||
url={origin.host} | ||
/> | ||
<ContentMessage | ||
heading={t("content", { | ||
connector: tCommon( | ||
`connectors.${connector as "lndhub"}` /* Type hack */ | ||
), | ||
})} | ||
content={name} | ||
/> | ||
</div> | ||
<ConfirmOrCancel | ||
disabled={loading} | ||
loading={loading} | ||
onConfirm={confirm} | ||
onCancel={reject} | ||
/> | ||
</Container> | ||
</div> | ||
); | ||
} | ||
|
||
export default ConfirmAddAccount; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
src/extension/background-script/actions/accounts/promptAdd.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import utils from "~/common/lib/utils"; | ||
import { Message } from "~/types"; | ||
|
||
export default async function promptAddAccount(message: Message) { | ||
if (typeof message.args.name !== "string") { | ||
return { | ||
error: "Name missing.", | ||
}; | ||
} | ||
|
||
if (typeof message.args.connector !== "string") { | ||
return { | ||
error: "Connector missing.", | ||
}; | ||
} | ||
|
||
if (typeof message.args.config !== "object") { | ||
return { | ||
error: "Config missing.", | ||
}; | ||
} | ||
|
||
try { | ||
await utils.openPrompt({ | ||
...message, | ||
action: "confirmAddAccount", | ||
}); | ||
return { data: { success: true } }; | ||
} catch (e) { | ||
console.error("Adding account cancelled", e); | ||
if (e instanceof Error) { | ||
return { success: false, error: e.message }; | ||
} | ||
return { success: false }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import browser from "webextension-polyfill"; | ||
|
||
import getOriginData from "./originData"; | ||
import shouldInject from "./shouldInject"; | ||
|
||
// Alby calls that can be executed from the AlbyProvider. | ||
// Update when new calls are added | ||
const albyCalls = ["alby/enable", "alby/addAccount"]; | ||
// calls that can be executed when alby is not enabled for the current content page | ||
const disabledCalls = ["alby/enable"]; | ||
|
||
let isEnabled = false; // store if alby is enabled for this content page | ||
let isRejected = false; // store if the alby enable call failed. if so we do not prompt again | ||
let callActive = false; // store if a alby call is currently active. Used to prevent multiple calls in parallel | ||
|
||
async function init() { | ||
const inject = await shouldInject(); | ||
if (!inject) { | ||
return; | ||
} | ||
|
||
// message listener to listen to inpage alby calls | ||
// those calls get passed on to the background script | ||
// (the inpage script can not do that directly, but only the inpage script can make alby available to the page) | ||
window.addEventListener("message", (ev) => { | ||
// Only accept messages from the current window | ||
if ( | ||
ev.source !== window || | ||
ev.data.application !== "LBE" || | ||
ev.data.scope !== "alby" | ||
) { | ||
return; | ||
} | ||
|
||
if (ev.data && !ev.data.response) { | ||
// if an enable call railed we ignore the request to prevent spamming the user with prompts | ||
if (isRejected) { | ||
postMessage(ev, { | ||
error: | ||
"window.alby call cancelled (rejecting further window.alby calls until the next reload)", | ||
}); | ||
return; | ||
} | ||
// if a call is active we ignore the request | ||
if (callActive) { | ||
postMessage(ev, { error: "window.alby call already executing" }); | ||
return; | ||
} | ||
// limit the calls that can be made from window.alby | ||
// only listed calls can be executed | ||
// if not enabled only enable can be called. | ||
const availableCalls = isEnabled ? albyCalls : disabledCalls; | ||
if (!availableCalls.includes(ev.data.action)) { | ||
console.error("Function not available."); | ||
return; | ||
} | ||
|
||
const messageWithOrigin = { | ||
// every call call is scoped in `public` | ||
// this prevents websites from accessing internal actions | ||
action: `public/${ev.data.action}`, | ||
args: ev.data.args, | ||
application: "LBE", | ||
public: true, // indicate that this is a public call from the content script | ||
prompt: true, | ||
origin: getOriginData(), | ||
}; | ||
|
||
const replyFunction = (response) => { | ||
callActive = false; // reset call is active | ||
// if it is the enable call we store if alby is enabled for this content script | ||
if (ev.data.action === "alby/enable") { | ||
isEnabled = response.data?.enabled; | ||
if (response.error) { | ||
console.error(response.error); | ||
console.info("Enable was rejected ignoring further alby calls"); | ||
isRejected = true; | ||
} | ||
} | ||
postMessage(ev, response); | ||
}; | ||
callActive = true; | ||
return browser.runtime | ||
.sendMessage(messageWithOrigin) | ||
.then(replyFunction) | ||
.catch(replyFunction); | ||
} | ||
}); | ||
} | ||
|
||
function postMessage(ev, response) { | ||
window.postMessage( | ||
{ | ||
id: ev.data.id, | ||
application: "LBE", | ||
response: true, | ||
data: response, | ||
scope: "alby", | ||
}, | ||
"*" | ||
); | ||
} | ||
|
||
init(); | ||
|
||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import AlbyProvider from "../providers/alby"; | ||
|
||
if (document) { | ||
window.alby = new AlbyProvider(); | ||
} |
Oops, something went wrong.