Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: externally_connectable CAIP delivery and enveloping #25075

Merged
merged 57 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e0c7edb
WIP
jiexi Jun 3, 2024
370dc06
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 3, 2024
c1ae3db
WIP
jiexi Jun 5, 2024
61e9697
WIP PortStream bypass sanity check (working)
jiexi Jun 5, 2024
1f8cfd2
WIP wrapped stream (working)
jiexi Jun 5, 2024
5db9a97
cleanup inpage
jiexi Jun 5, 2024
6ef86a4
DRY caip stream
jiexi Jun 5, 2024
97469f9
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 5, 2024
1f58e7e
Rename. WIP spec
jiexi Jun 5, 2024
a9b741f
add SplitStream specs
jiexi Jun 5, 2024
7df64f3
add CaipToMultiplexStream, MultiplexToCaipStream specs
jiexi Jun 5, 2024
7db9d75
lint
jiexi Jun 5, 2024
65c9d68
WIP createCaipStream spec
jiexi Jun 5, 2024
c8b66b5
add createCaipStream specs
jiexi Jun 6, 2024
bbb33ae
lint
jiexi Jun 6, 2024
edab0fe
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 6, 2024
040d300
add BARAD_DUR flag
jiexi Jun 6, 2024
2acb719
dry background trackDappView
jiexi Jun 6, 2024
9792594
move externally_connectable manifest wildcard behind BARAD_DUR
jiexi Jun 6, 2024
7372604
jsdoc
jiexi Jun 6, 2024
b82888b
restore inpage
jiexi Jun 11, 2024
64ca655
Move caip stream closer to provider. Replace caip<->multiplex transfo…
jiexi Jun 11, 2024
714d044
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 11, 2024
29ea68c
Rename connectExternalDapp to connectExternalCaip
jiexi Jun 11, 2024
64ba990
actually restore inpage
jiexi Jun 11, 2024
46bfee7
Fix createCaipStream specs
jiexi Jun 11, 2024
e24ef63
use createDeferredPromise instead
jiexi Jun 11, 2024
379ce8a
rename onData to readFromStream
jiexi Jun 12, 2024
98ff148
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 12, 2024
cd3dd02
fix method names. add setupUntrustedCommunicationCaip
jiexi Jun 12, 2024
7f1eb8a
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 12, 2024
cbfd014
lint
jiexi Jun 12, 2024
5d65634
Merge remote-tracking branch 'origin/jl/mmp-2528/externally_connectab…
jiexi Jun 12, 2024
3652ab3
lint
jiexi Jun 12, 2024
a239e64
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 13, 2024
4f4f999
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 14, 2024
5b667f2
Rename connectExternalLegacy to connectExternalExtension
jiexi Jun 14, 2024
0c3f000
rename _subjectType to inputSubjectType
jiexi Jun 14, 2024
ab7767b
use messenger where possible
jiexi Jun 18, 2024
7fc0b23
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 18, 2024
ccd10ab
Rename setupUntrustedCommunicationLegacy to setupUntrustedCommunicati…
jiexi Jun 18, 2024
2eeac73
lint
jiexi Jun 18, 2024
600daed
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 21, 2024
ee4dec5
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 21, 2024
dc6c189
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 21, 2024
d27526a
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 24, 2024
571cf9e
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 25, 2024
1ced8f3
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 25, 2024
487b9ca
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 26, 2024
323ab1e
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 26, 2024
7d3d5f6
Bifurcate streams
jiexi Jun 26, 2024
2258ee7
Merge branch 'develop' into jl/mmp-2528/externally_connectable-caip-e…
jiexi Jun 26, 2024
3c8b832
fix specs
jiexi Jun 26, 2024
439f27e
Update app/scripts/metamask-controller.js
jiexi Jun 26, 2024
9f35203
remove requestAccountTabIds for CAIP
jiexi Jun 26, 2024
fa34c32
Merge remote-tracking branch 'origin/jl/mmp-2528/externally_connectab…
jiexi Jun 26, 2024
c8ce2f8
lint
jiexi Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/manifest/v2/_barad_dur.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"externally_connectable": {
"matches": ["http://*/*", "https://*/*"],
"ids": ["*"]
}
}
6 changes: 6 additions & 0 deletions app/manifest/v3/_barad_dur.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"externally_connectable": {
"matches": ["http://*/*", "https://*/*"],
"ids": ["*"]
}
}
125 changes: 99 additions & 26 deletions app/scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { checkForLastErrorAndLog } from '../../shared/modules/browser-runtime.ut
import { isManifestV3 } from '../../shared/modules/mv3.utils';
import { maskObject } from '../../shared/modules/object.utils';
import { FIXTURE_STATE_METADATA_VERSION } from '../../test/e2e/default-fixture';
import { createCaipStream } from '../../shared/modules/caip-stream';
import migrations from './migrations';
import Migrator from './lib/migrator';
import ExtensionPlatform from './platforms/extension';
Expand Down Expand Up @@ -195,7 +196,8 @@ const sendReadyMessageToTabs = async () => {

// These are set after initialization
let connectRemote;
let connectExternal;
let connectExternalLegacy;
let connectExternalDapp;

browser.runtime.onConnect.addListener(async (...args) => {
// Queue up connection attempts here, waiting until after initialization
Expand All @@ -208,7 +210,13 @@ browser.runtime.onConnectExternal.addListener(async (...args) => {
// Queue up connection attempts here, waiting until after initialization
await isInitialized;
// This is set in `setupController`, which is called as part of initialization
connectExternal(...args);
const port = args[0];

if (port.sender.tab?.id && process.env.BARAD_DUR) {
adonesky1 marked this conversation as resolved.
Show resolved Hide resolved
connectExternalDapp(...args);
} else {
connectExternalLegacy(...args);
}
});

function saveTimestamp() {
Expand Down Expand Up @@ -517,6 +525,47 @@ function emitDappViewedMetricEvent(
}
}

/**
* Track dapp connection when loaded and permissioned
*
* @param {Port} remotePort - The port provided by a new context.
* @param {object} preferencesController - Preference Controller to get total created accounts
* @param {object} permissionController - Permission Controller to check if origin is permitted
*/
function trackDappView(
remotePort,
preferencesController,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We've been trying to move away from passing around controller references as arguments, as we found it makes it easy to miss things when making breaking changes to controllers.

I see that this is pre-existing in this case though, so maybe we can clean this up later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the preference to pass a callback in instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. The preferences is to use the messenger, or callbacks for code not setup with a messenger.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using the messenger where possible now ab7767b

permissionController,
) {
if (!remotePort.sender || !remotePort.sender.tab || !remotePort.sender.url) {
return;
}
const tabId = remotePort.sender.tab.id;
const url = new URL(remotePort.sender.url);
const { origin } = url;

// store the orgin to corresponding tab so it can provide infor for onActivated listener
if (!Object.keys(tabOriginMapping).includes(tabId)) {
tabOriginMapping[tabId] = origin;
}
const connectSitePermissions = permissionController.state.subjects[origin];
// when the dapp is not connected, connectSitePermissions is undefined
const isConnectedToDapp = connectSitePermissions !== undefined;
// when open a new tab, this event will trigger twice, only 2nd time is with dapp loaded
const isTabLoaded = remotePort.sender.tab.title !== 'New Tab';

// *** Emit DappViewed metric event when ***
// - refresh the dapp
// - open dapp in a new tab
if (isConnectedToDapp && isTabLoaded) {
emitDappViewedMetricEvent(
origin,
connectSitePermissions,
preferencesController,
);
}
}

/**
* Initializes the MetaMask Controller with any initial state and default language.
* Configures platform-specific error reporting strategy.
Expand Down Expand Up @@ -734,27 +783,11 @@ export function setupController(
const url = new URL(remotePort.sender.url);
const { origin } = url;

// store the orgin to corresponding tab so it can provide infor for onActivated listener
if (!Object.keys(tabOriginMapping).includes(tabId)) {
tabOriginMapping[tabId] = origin;
}
const connectSitePermissions =
controller.permissionController.state.subjects[origin];
// when the dapp is not connected, connectSitePermissions is undefined
const isConnectedToDapp = connectSitePermissions !== undefined;
// when open a new tab, this event will trigger twice, only 2nd time is with dapp loaded
const isTabLoaded = remotePort.sender.tab.title !== 'New Tab';

// *** Emit DappViewed metric event when ***
// - refresh the dapp
// - open dapp in a new tab
if (isConnectedToDapp && isTabLoaded) {
emitDappViewedMetricEvent(
origin,
connectSitePermissions,
controller.preferencesController,
);
}
trackDappView(
remotePort,
controller.preferencesController,
controller.permissionController,
);

remotePort.onMessage.addListener((msg) => {
if (
Expand All @@ -765,12 +798,12 @@ export function setupController(
}
});
}
connectExternal(remotePort);
connectExternalLegacy(remotePort);
}
};

// communication with page or other extension
connectExternal = (remotePort) => {
connectExternalLegacy = (remotePort) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Maybe we could call this connectExternalExtension instead, to better reflect what it does. Even after we ship this, it won't really be a legacy feature.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess technically it was also used for the desktop connection, though that has since been removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah good point. Also, we have an existing legacy stream already haha. 5b667f2

///: BEGIN:ONLY_INCLUDE_IF(desktop)
if (
DesktopManager.isDesktopEnabled() &&
Expand All @@ -789,8 +822,48 @@ export function setupController(
});
};

connectExternalDapp = async (remotePort) => {
if (metamaskBlockedPorts.includes(remotePort.name)) {
return;
}

// this is triggered when a new tab is opened, or origin(url) is changed
if (remotePort.sender && remotePort.sender.tab && remotePort.sender.url) {
const tabId = remotePort.sender.tab.id;
const url = new URL(remotePort.sender.url);
const { origin } = url;

trackDappView(
remotePort,
controller.preferencesController,
controller.permissionController,
);

// TODO: remove this when we separate the legacy and multichain rpc pipelines
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious to know what this refers to, i.e. what does it mean to "separate the legacy and multichain RPC pipelines", and how is this requestAccountTabIds state related?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gudahtt we are intending to create a separate JSON RPC pipeline for the new API (ticket here) for long term maintainability

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gudahtt just want to confirm you've seen and understood this roadmap?

remotePort.onMessage.addListener((msg) => {
if (
msg.type === 'caip-x' &&
jiexi marked this conversation as resolved.
Show resolved Hide resolved
msg.data &&
msg.data.method === MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS
) {
requestAccountTabIds[origin] = tabId;
}
});
}

const portStream =
overrides?.getPortStream?.(remotePort) || new PortStream(remotePort);

const connectionStream = createCaipStream(portStream);

controller.setupUntrustedCommunication({
connectionStream,
sender: remotePort.sender,
});
};

if (overrides?.registerConnectListeners) {
overrides.registerConnectListeners(connectRemote, connectExternal);
overrides.registerConnectListeners(connectRemote, connectExternalLegacy);
}

//
Expand Down
15 changes: 7 additions & 8 deletions app/scripts/inpage.js
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes in this file need to be moved into the test-dapp. Only here for local testing/verification and to demonstrate how the CAIP Stream pipeline in the inpage provider is exactly the same one used in background

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Revert this before merge

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relevant poc test-dapp that enables externally_connectable without caip-x enveloping

https://github.com/MetaMask/test-dapp/pull/317/files

Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ cleanContextForImports();
/* eslint-disable import/first */
adonesky1 marked this conversation as resolved.
Show resolved Hide resolved
import log from 'loglevel';
import { v4 as uuid } from 'uuid';
import { WindowPostMessageStream } from '@metamask/post-message-stream';
import PortStream from 'extension-port-stream';
import { initializeProvider } from '@metamask/providers/dist/initializeInpageProvider';
import shouldInjectProvider from '../../shared/modules/provider-injection';
import { createCaipStream } from '../../shared/modules/caip-stream';

// contexts
const CONTENT_SCRIPT = 'metamask-contentscript';
const INPAGE = 'metamask-inpage';
const EXTENSION_ID = 'nonfpcflonapegmnfeafnddgdniflbnk';

restoreContextAfterImports();

Expand All @@ -51,13 +51,12 @@ log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn');

if (shouldInjectProvider()) {
// setup background connection
const metamaskStream = new WindowPostMessageStream({
name: INPAGE,
target: CONTENT_SCRIPT,
});
const extensionPort = chrome.runtime.connect(EXTENSION_ID);
const portStream = new PortStream(extensionPort);
const connectionStream = createCaipStream(portStream);

initializeProvider({
connectionStream: metamaskStream,
connectionStream,
logger: log,
shouldShimWeb3: true,
providerInfo: {
Expand Down
2 changes: 2 additions & 0 deletions builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ env:
- MULTICHAIN: ''
# Determines if feature flagged Multichain Transactions should be used
- TRANSACTION_MULTICHAIN: ''
# Determines if Barad Dur features should be used
- BARAD_DUR: ''
# Determines if feature flagged Chain permissions
- CHAIN_PERMISSIONS: ''
# Enables use of test gas fee flow to debug gas fee estimation
Expand Down
4 changes: 4 additions & 0 deletions development/build/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const IS_MV3_ENABLED =
const baseManifest = IS_MV3_ENABLED
? require('../../app/manifest/v3/_base.json')
: require('../../app/manifest/v2/_base.json');
const baradDurManifest = IS_MV3_ENABLED
? require('../../app/manifest/v3/_barad_dur.json')
: require('../../app/manifest/v2/_barad_dur.json');
const { loadBuildTypesConfig } = require('../lib/build-type');

const { TASKS, ENVIRONMENT } = require('./constants');
Expand Down Expand Up @@ -41,6 +44,7 @@ function createManifestTasks({
);
const result = mergeWith(
cloneDeep(baseManifest),
process.env.BARAD_DUR ? cloneDeep(baradDurManifest) : {},
platformModifications,
adonesky1 marked this conversation as resolved.
Show resolved Hide resolved
browserVersionMap[platform],
await getBuildModifications(buildType, platform),
Expand Down
Loading
Loading