Skip to content

Commit

Permalink
Merge branch 'develop' into MMI-snapshots-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
zone-live authored Feb 22, 2024
2 parents 1d9dce6 + 81c1593 commit 3e4472d
Show file tree
Hide file tree
Showing 32 changed files with 400 additions and 421 deletions.
22 changes: 18 additions & 4 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,26 @@ When you're done with your project / bugfix / feature and ready to submit a PR,

- [ ] **Make sure you followed our [`coding guidelines`](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md)**: These guidelines aim to maintain consistency and readability across the codebase. They help ensure that the code is easy to understand, maintain, and modify, which is particularly important when working with multiple contributors.
- [ ] **Test it**: For any new programmatic functionality, we like unit tests when possible, so if you can keep your code cleanly isolated, please do add a test file to the `tests` folder.
- [ ] **Add to the CHANGELOG**: Help us keep track of all the moving pieces by adding an entry to the [`CHANGELOG.md`](https://github.com/MetaMask/metamask-extension/blob/develop/CHANGELOG.md) with a link to your PR.
- [ ] **Meet the spec**: Make sure the PR adds functionality that matches the issue you're closing. This is especially important for bounties: sometimes design or implementation details are included in the conversation, so read carefully!
- [ ] **Close the issue**: If this PR closes an open issue, add the line `Fixes #$ISSUE_NUMBER`. Ex. For closing issue 418, include the line `Fixes #418`. If it doesn't close the issue but addresses it partially, just include a reference to the issue number, like `#418`.
- [ ] **Close the issue**: If this PR closes an open issue, fill out the "Related issues" section with `Fixes: #$ISSUE_NUMBER`. Ex. For closing issue 418, include the line `Fixes: #418`. If it doesn't close the issue but addresses it partially, just include a reference to the issue number, like `#418`.
- [ ] **Keep it simple**: Try not to include multiple features in a single PR, and don't make extraneous changes outside the scope of your contribution. All those touched files make things harder to review ;)
- [ ] **PR against `develop`**: Submit your PR against the `develop` branch. This is where we merge new features so they get some time to receive extra testing before being pushed to `master` for production. If your PR is a hot-fix that needs to be published urgently, you may submit a PR against the `master` branch, but this PR will receive tighter scrutiny before merging.
- [ ] **Get reviewed by a core contributor**: Make sure you get a `:thumbsup`, `:+1`, or `LGTM` from a user with a `Member` badge before merging.
- [ ] **Ensure the PR is correctly labeled.**: More detail about labels definitions can be found [here](https://github.com/MetaMask/metamask-extension/blob/develop/.github/LABELING_GUIDELINES.md).
- [ ] **Get reviewed by MetaMask Internal Developers**: All PRs require 2 approvals from MetaMask Internal Developers before merging.
- [ ] **Ensure the PR is correctly labeled.**: More detail about PR labels can be found [here](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md).
- [ ] **PR Titles**: Must adhere to the [Conventional Commits specification](https://www.conventionalcommits.org)
- `<type>[optional scope]: <description>`
- Example: `feat(parser): add ability to parse arrays`
- Available types:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing tests or correcting existing tests
- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- chore: Other changes that don't modify src or test files
- revert: Reverts a previous commit

And that's it! Thanks for helping out.
13 changes: 13 additions & 0 deletions .github/workflows/validate-conventional-commits.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Validate Conventional Commit Title
on:
pull_request:
types: [opened, edited, reopened]

jobs:
pr-title-linter:
runs-on: ubuntu-latest
steps:
# this is a hash for amannn/[email protected]
- uses: amannn/action-semantic-pull-request@c3cd5d1ea3580753008872425915e343e351ab54
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion app/manifest/v3/chrome.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'none'; frame-ancestors 'self';"
"extension_pages": "script-src 'self'; object-src 'none'; frame-ancestors 'none';"
},
"externally_connectable": {
"matches": ["https://metamask.io/*"],
Expand Down
9 changes: 5 additions & 4 deletions app/scripts/app-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,11 @@ const registerInPageContentScript = async () => {
registerInPageContentScript();

/**
* Creates an offscreen document that can be used to load iframes containing
* scripts that can communicate with the extension through the chrome runtime
* API. Only one offscreen document may exist, so iframes are used within the
* created offscreen document. See the offscreen folder for more details.
* Creates an offscreen document that can be used to load additional scripts
* and iframes that can communicate with the extension through the chrome
* runtime API. Only one offscreen document may exist, so any iframes required
* by extension can be embedded in the offscreen.html file. See the offscreen
* folder for more details.
*/
async function createOffscreen() {
if (await chrome.offscreen.hasDocument()) {
Expand Down
16 changes: 8 additions & 8 deletions app/scripts/lib/offscreen-bridge/lattice-offscreen-keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import {
* _getCreds method calls into window.open to open a new window for the lattice
* connector. The solution here is to split the keyring execution so that the
* portion that requires a normal functioning DOM is executed in the offscreen
* document. The lattice-iframe.ts file in the offscreen directory is
* responsible for the latter half of the original keyrings execution. The main
* difference in the first half that this overwritten method is responsible for
* is just to use the chrome.runtime.sendMessage method to send a message to
* the offscreen document which picks up on the execution of opening the new
* window to the lattice connector. Note that this file differs from the
* ledger and trezor offscreen bridges because this keyring requires no bridge
* to function appropriately.
* document. The lattice.ts file in the offscreen directory is responsible for
* the latter half of the original keyrings execution. The main difference in
* the first half that this overwritten method is responsible for is just to
* use the chrome.runtime.sendMessage method to send a message to the offscreen
* document which picks up on the execution of opening the new window to the
* lattice connector. Note that this file differs from the ledger and trezor
* offscreen bridges because this keyring requires no bridge to function
* appropriately.
*/
class LatticeKeyringOffscreen extends LatticeKeyring {
static type: string;
Expand Down
7 changes: 4 additions & 3 deletions app/scripts/lib/offscreen-bridge/ledger-offscreen-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
* that the keyring can call into for specific functions. The bridge then makes
* whatever calls or requests it needs to in order to fulfill the request from
* the keyring. In this case, the bridge is used to communicate with the
* Offscreen Document. Inside the Offscreen document the ledger-iframe is
* embedded that will listen for these calls and communicate with the
* ledger device via the ledger keyring iframe.
* Offscreen Document. Inside the Offscreen document the ledger script is
* loaded and registers a listener for these calls and communicate with the
* ledger device via the ledger keyring iframe. The ledger keyring iframe is
* added to the offscreen.html file directly.
*/
export class LedgerOffscreenBridge implements LedgerBridge {
isDeviceConnected = false;
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/lib/offscreen-bridge/trezor-offscreen-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {
* that the keyring can call into for specific functions. The bridge then makes
* whatever calls or requests it needs to in order to fulfill the request from
* the keyring. In this case, the bridge is used to communicate with the
* Offscreen Document. Inside the Offscreen document the trezor-iframe is
* embedded that will listen for these calls and communicate with the
* Offscreen Document. Inside the Offscreen document the trezor script is
* loaded and registers a listener for these calls and communicate with the
* trezor/connect-web library.
*/
export class TrezorOffscreenBridge implements TrezorBridge {
Expand Down
43 changes: 1 addition & 42 deletions development/build/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,7 @@ function createScriptTasks({
// In MV3 we will need to build our offscreen entry point bundle and any
// entry points for iframes that we want to lockdown with LavaMoat.
if (process.env.ENABLE_MV3 === 'true') {
standardEntryPoints.push(
'offscreen',
'trezor-iframe',
'ledger-iframe',
'lattice-iframe',
);
standardEntryPoints.push('offscreen');
}

const standardSubtask = createTask(
Expand All @@ -327,12 +322,6 @@ function createScriptTasks({
return './app/vendor/trezor/content-script.js';
case 'offscreen':
return './offscreen/scripts/offscreen.ts';
case 'trezor-iframe':
return './offscreen/scripts/trezor-iframe.ts';
case 'ledger-iframe':
return './offscreen/scripts/ledger-iframe.ts';
case 'lattice-iframe':
return './offscreen/scripts/lattice-iframe.ts';
default:
return `./app/scripts/${label}.js`;
}
Expand Down Expand Up @@ -840,36 +829,6 @@ function createFactoredBuild({
});
break;
}
case 'trezor-iframe': {
renderJavaScriptLoader({
groupSet,
commonSet,
browserPlatforms,
applyLavaMoat,
destinationFileName: 'load-trezor-iframe.js',
});
break;
}
case 'ledger-iframe': {
renderJavaScriptLoader({
groupSet,
commonSet,
browserPlatforms,
applyLavaMoat,
destinationFileName: 'load-ledger-iframe.js',
});
break;
}
case 'lattice-iframe': {
renderJavaScriptLoader({
groupSet,
commonSet,
browserPlatforms,
applyLavaMoat,
destinationFileName: 'load-lattice-iframe.js',
});
break;
}
default: {
throw new Error(
`build/scripts - unknown groupLabel "${groupLabel}"`,
Expand Down
10 changes: 0 additions & 10 deletions offscreen/lattice-iframe.html

This file was deleted.

14 changes: 0 additions & 14 deletions offscreen/ledger-iframe.html

This file was deleted.

7 changes: 4 additions & 3 deletions offscreen/offscreen.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
</head>
<body>
<script type="text/javascript" src="./load-offscreen.js"></script>
<iframe src="./trezor-iframe.html"></iframe>
<iframe src="./ledger-iframe.html"></iframe>
<iframe src="./lattice-iframe.html"></iframe>
<iframe
src="https://metamask.github.io/eth-ledger-bridge-keyring"
allow="hid"
></iframe>
</body>
</html>
86 changes: 0 additions & 86 deletions offscreen/scripts/lattice-iframe.ts

This file was deleted.

91 changes: 91 additions & 0 deletions offscreen/scripts/lattice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
KnownOrigins,
OffscreenCommunicationTarget,
} from '../../shared/constants/offscreen-communication';

async function openConnectorTab(url: string) {
const browserTab = window.open(url);
if (!browserTab) {
throw new Error('Failed to open Lattice connector.');
}

return browserTab;
}

export default function init() {
/**
* The main element of the eth-lattice-keyring library that is impacted by MV3
* is the _openConnectorTab method which is responsible for opening a tab to
* the lattice connector. This method is called by the _getCreds method of the
* keyring. In the default keyring this would be attempted inside the service
* worker which has no DOM and therefore would fail. The solution is to split
* the functionality so that the openConnectorTab portion operates inside the
* offscreen document with its DOM. That is what this file is responsible for.
*
* When receiving a message from the service worker script targeting the
* lattice iframe, this listener will execute and open the new tab for
* connecting to the lattice device. The response from the lattice connector
* is then sent back to the offscreen bridge for lattice, which extends from
* the eth-lattice-keyring Keyring class.
*/
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
if (msg.target !== OffscreenCommunicationTarget.latticeOffscreen) {
return;
}

// Open the tab
openConnectorTab(msg.params.url).then((browserTab) => {
// Watch for the open window closing before creds are sent back
const listenInterval = setInterval(() => {
if (browserTab.closed) {
clearInterval(listenInterval);
sendResponse({
error: new Error('Lattice connector closed.'),
});
}
}, 500);

// On a Chromium browser we can just listen for a window message from the
// lattice tab (using the event.origin property). When we get that it'll be
// the response from the lattice connector with the deviceID and password.
// We can then forward that response to the lattice-offscreen-keyring's
// _getCreds method using sendResponse API from the chrome runtime.
window.addEventListener(
'message',
(event) => {
// Ensure origin
if (
event.origin !== KnownOrigins.lattice &&
event.source === browserTab
) {
return;
}

try {
// Stop the listener
clearInterval(listenInterval);

// Parse and return creds
const creds = JSON.parse(event.data);
if (!creds.deviceID || !creds.password) {
sendResponse({
error: new Error('Invalid credentials returned from Lattice.'),
});
}
sendResponse({
result: creds,
});
} catch (err) {
sendResponse({
error: err,
});
}
},
false,
);
});

// eslint-disable-next-line consistent-return
return true;
});
}
Loading

0 comments on commit 3e4472d

Please sign in to comment.