Skip to content

Commit

Permalink
Sollet Chrome Extension v0 (project-serum#127)
Browse files Browse the repository at this point in the history
* init

* ui changes

* injection

* upd

* adding connections page

* upd extension

* merge

* prettier

* fix

* fix

* fix
  • Loading branch information
jhlx authored Mar 14, 2021
1 parent 2664ed7 commit 754dd37
Show file tree
Hide file tree
Showing 26 changed files with 944 additions and 192 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ yarn-error.log*

.idea
.eslintcache

# generate with `build:extension` script
extension/build/*
70 changes: 70 additions & 0 deletions extension/src/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const responseHandlers = new Map();

function launchPopup(message, sender, sendResponse) {
const searchParams = new URLSearchParams();
searchParams.set('origin', sender.origin);
searchParams.set('network', message.data.params.network);
searchParams.set('request', JSON.stringify(message.data));

// TODO consolidate popup dimensions
chrome.windows.getLastFocused((focusedWindow) => {
chrome.windows.create({
url: 'index.html/#' + searchParams.toString(),
type: 'popup',
width: 375,
height: 600,
top: focusedWindow.top,
left: focusedWindow.left + (focusedWindow.width - 375),
setSelfAsOpener: true,
focused: true,
});
});

responseHandlers.set(message.data.id, sendResponse);
}

function handleConnect(message, sender, sendResponse) {
chrome.storage.local.get('connectedWallets', (result) => {
const connectedWallet = (result.connectedWallets || {})[sender.origin];
if (!connectedWallet) {
launchPopup(message, sender, sendResponse);
} else {
sendResponse({
method: 'connected',
params: {
publicKey: connectedWallet.publicKey,
autoApprove: connectedWallet.autoApprove,
},
id: message.data.id,
});
}
});
}

function handleDisconnect(message, sender, sendResponse) {
chrome.storage.local.get('connectedWallets', (result) => {
delete result.connectedWallets[sender.origin];
chrome.storage.local.set(
{ connectedWallets: result.connectedWallets },
() => sendResponse({ method: 'disconnected', id: message.data.id }),
);
});
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.channel === 'sollet_contentscript_background_channel') {
if (message.data.method === 'connect') {
handleConnect(message, sender, sendResponse);
} else if (message.data.method === 'disconnect') {
handleDisconnect(message, sender, sendResponse);
} else {
launchPopup(message, sender, sendResponse);
}
// keeps response channel open
return true;
} else if (message.channel === 'sollet_extension_background_channel') {
const responseHandler = responseHandlers.get(message.data.id);
responseHandlers.delete(message.data.id);
responseHandler(message.data);
}
});
24 changes: 24 additions & 0 deletions extension/src/contentscript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const container = document.head || document.documentElement;
const scriptTag = document.createElement('script');
scriptTag.setAttribute('async', 'false');
scriptTag.src = chrome.runtime.getURL('script.js');
container.insertBefore(scriptTag, container.children[0]);
container.removeChild(scriptTag);

window.addEventListener('sollet_injected_script_message', (event) => {
chrome.runtime.sendMessage(
{
channel: 'sollet_contentscript_background_channel',
data: event.detail,
},
(response) => {
// Can return null response if window is killed
if (!response) {
return;
}
window.dispatchEvent(
new CustomEvent('sollet_contentscript_message', { detail: response }),
);
},
);
});
35 changes: 35 additions & 0 deletions extension/src/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "Sollet",
"description": "Solana SPL Token Wallet",
"version": "0.1",
"browser_action": {
"default_popup": "index.html",
"default_title": "Open the popup"
},
"manifest_version": 2,
"icons": {
"16": "favicon.ico",
"192": "logo192.png",
"512": "logo512.png"
},
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"permissions": [
"storage"
],
"content_scripts": [
{
"matches": ["file://*/*", "http://*/*", "https://*/*"],
"js": [
"contentscript.js"
],
"run_at": "document_start",
"all_frames": true
}
],
"web_accessible_resources": ["script.js"],
"content_security_policy": "script-src 'self' 'sha256-ek+jXksbUr00x+EdLLqiv69t8hATh5rPjHVvVVGA9ms='; object-src 'self'"
}

15 changes: 15 additions & 0 deletions extension/src/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
window.sollet = {
postMessage: (message) => {
const listener = (event) => {
if (event.detail.id === message.id) {
window.removeEventListener('sollet_contentscript_message', listener);
window.postMessage(event.detail);
}
};
window.addEventListener('sollet_contentscript_message', listener);

window.dispatchEvent(
new CustomEvent('sollet_injected_script_message', { detail: message }),
);
},
};
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,21 @@
"predeploy": "git pull --ff-only && yarn && yarn build",
"deploy": "gh-pages -d build",
"fix": "run-s fix:*",
"fix:prettier": "prettier \"src/**/*.js\" --write",
"fix:prettier": "prettier \"src/**/*.js\" \"extension/src/*.js\" --write",
"start": "react-scripts start",
"build": "react-scripts build",
"build:extension": "yarn build && cp -a ./build/. ./extension/build/ && yarn build:extension-scripts",
"build:extension-scripts": "cp -a ./extension/src/. ./extension/build/.",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
"env": {
"browser": true,
"es6": true,
"webextensions": true
},
"extends": ["react-app"]
},
"jest": {
"transformIgnorePatterns": [
Expand Down
37 changes: 29 additions & 8 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ import NavigationFrame from './components/NavigationFrame';
import { ConnectionProvider } from './utils/connection';
import WalletPage from './pages/WalletPage';
import { useWallet, WalletProvider } from './utils/wallet';
import { ConnectedWalletsProvider } from './utils/connected-wallets';
import LoadingIndicator from './components/LoadingIndicator';
import { SnackbarProvider } from 'notistack';
import PopupPage from './pages/PopupPage';
import LoginPage from './pages/LoginPage';
import ConnectionsPage from './pages/ConnectionsPage';
import { isExtension } from './utils/utils';
import { PageProvider, usePage } from './utils/page';

export default function App() {
// TODO: add toggle for dark mode
Expand All @@ -25,6 +29,8 @@ export default function App() {
type: prefersDarkMode ? 'dark' : 'light',
primary: blue,
},
// TODO consolidate popup dimensions
ext: '450',
}),
[prefersDarkMode],
);
Expand All @@ -34,20 +40,30 @@ export default function App() {
return null;
}

let appElement = (
<NavigationFrame>
<Suspense fallback={<LoadingIndicator />}>
<PageContents />
</Suspense>
</NavigationFrame>
);

if (isExtension) {
appElement = (
<ConnectedWalletsProvider>
<PageProvider>{appElement}</PageProvider>
</ConnectedWalletsProvider>
);
}

return (
<Suspense fallback={<LoadingIndicator />}>
<ThemeProvider theme={theme}>
<CssBaseline />

<ConnectionProvider>
<SnackbarProvider maxSnack={5} autoHideDuration={8000}>
<WalletProvider>
<NavigationFrame>
<Suspense fallback={<LoadingIndicator />}>
<PageContents />
</Suspense>
</NavigationFrame>
</WalletProvider>
<WalletProvider>{appElement}</WalletProvider>
</SnackbarProvider>
</ConnectionProvider>
</ThemeProvider>
Expand All @@ -57,11 +73,16 @@ export default function App() {

function PageContents() {
const wallet = useWallet();
const [page] = usePage();
if (!wallet) {
return <LoginPage />;
}
if (window.opener) {
return <PopupPage opener={window.opener} />;
}
return <WalletPage />;
if (page === 'wallet') {
return <WalletPage />;
} else if (page === 'connections') {
return <ConnectionsPage />;
}
}
Loading

0 comments on commit 754dd37

Please sign in to comment.