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

Request filtering in main process2 #16264

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

peter-sanderson
Copy link
Contributor

@peter-sanderson peter-sanderson commented Jan 8, 2025

Resolve #7171

  • This PR adds a whitelist for all requests coming out from the main thread.
  • Custom back-ends are dynamically whitelisted.

@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process branch from 0d4c182 to e9c5d25 Compare January 8, 2025 13:56
@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch 2 times, most recently from 4c3b80a to 7c52991 Compare January 9, 2025 11:02
Copy link

github-actions bot commented Jan 9, 2025

🚀 Expo preview is ready!

  • Project → trezor-suite-preview
  • Platforms → android, ios
  • Scheme → trezorsuitelite
  • Runtime Version → 21
  • More info

Learn more about 𝝠 Expo Github Action

@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch from 7c52991 to 80d2247 Compare January 9, 2025 11:18
@trezor-ci trezor-ci force-pushed the request-filtering-in-main-process branch from e9c5d25 to b5528cc Compare January 9, 2025 11:21
@peter-sanderson peter-sanderson changed the base branch from request-filtering-in-main-process to develop January 9, 2025 11:22
@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch 6 times, most recently from 2023d2c to 053106c Compare January 10, 2025 12:36
@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch from 053106c to 685fb18 Compare January 10, 2025 13:04
return whitelist.some(
whitelistedUrl =>
whitelistedUrl === hostname ||
// Todo: this .endsWith() seems fishy to me, why we need this?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I plan to try to remove this together with sldev in next PR and we'll see what breaks 😁

Copy link
Contributor

@Lemonexe Lemonexe Jan 14, 2025

Choose a reason for hiding this comment

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

Since this fn is called only with hostname extracted from the url, then we are safe that you cannot loophole it like that:
http://scammy-url.net?uselessParam=trezor.io

I think this is necessary to allows subdomains: btc1.trezor.io (would break? ), or anything.that.ends.with.trezor.io which is guaranteed not to be scammy-url.net so it's ok ✔️

@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch 4 times, most recently from 81d0bd8 to a40a5be Compare January 13, 2025 12:29
@@ -2,9 +2,14 @@ import path from 'path';
import http from 'http';
import WebSocket from 'ws';

// Todo: Currently this needs to be done in order to interceptor in test to work.
// This shall be taken care of, as we shall be intercepting the native fetch as well.
// import fetch from 'node-fetch';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@karliatto FYI, this is what we have been talking about


return;

case 'INTERCEPTED_HEADERS':
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Those events does not seem to be handled anywhere, despite being (potentially) emitted.

I am not sure if this switch is supposed to be actually exhaustive, but as those are not handled anywhere, else (and also not here originally).

@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch from a40a5be to 22d43d9 Compare January 13, 2025 17:27
@peter-sanderson peter-sanderson marked this pull request as ready for review January 13, 2025 17:28
@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch from 22d43d9 to 834759a Compare January 13, 2025 17:39
@@ -73,6 +76,9 @@ export const interceptNetSocketConnect = (context: InterceptorContext) => {
details = typeof callback === 'string' ? `${callback}:${request}` : request.toString();
}

const hostname = details.split(':')[0];
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: This is sub-optimal and it wont probably work in all scenarios. Any ideas?

return '';
};

const hostname = getHostname().split(':')[0] ?? '';
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: This is sub-optimal and it wont probably work in all scenarios. Any ideas?

Copy link
Contributor

Choose a reason for hiding this comment

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

as we discussed the new URL(address).hostname - I just now realised you could create a helper that would do it optionally, something like:

optionalGetUrlHostname = (address: string) => {
	try {
		return new URL(address).hostname;
	}
	catch(_err) {
		return null;
	}
}

then use it like hostname = optionalGetUrlHostname(address) ?? ''
file:///... ➡️ '' ✔️
invalid URLs ➡️ null ➡️ '' ✔️

@peter-sanderson peter-sanderson force-pushed the request-filtering-in-main-process2 branch from 834759a to e66a922 Compare January 13, 2025 17:53
Copy link
Contributor

@Lemonexe Lemonexe left a comment

Choose a reason for hiding this comment

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

Did not test yet, CR'd most of code, so dropping off comments 💬

callback,
validateRequest,
}: OverloadHttpRequestParams) => {
const hostname = typeof url === 'object' ? url.hostname ?? url.host ?? '' : '';
Copy link
Contributor

Choose a reason for hiding this comment

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

this means that for string url, hostname will always be '', which will always be false in isWhitelistedHost

mainThreadEmitter.emit('module/request-interceptor', {
type: 'ADD_WHITELISTED_DOMAIN',
domain: urlObj.hostname ?? urlObj.host,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

If I understand correctly this effectively adds coinjoin coordinator URL to allowed domains?

if (event.type === 'CIRCUIT_MISBEHAVING') {
mainThreadEmitter.emit('module/reset-tor-circuits', event);
default: {
const _exhaustiveCheck: never = event; // Poor-man's `switch-exhaustiveness-check`
Copy link
Contributor

Choose a reason for hiding this comment

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

why poor man's? This is absolutely fine 😄
Although typed record is better when mapping primitive values to cases, I would not use it to map functions. That would not read very well IMO.

return;

case 'SET_WHITELISTED_DOMAINS_FOR_CUSTOM_BACKENDS':
mainThreadAllowedDomain.customBackends[event.coin] = event.domains;
Copy link
Contributor

Choose a reason for hiding this comment

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

there is no reverse action when resetting a custom backend to default, so it will probably persist as enabled until you restart app or set custom backend again for the same coin.
I'm not saying it's needed, just a note. I think it's OK.


const urlObj = new URL(url);

return urlObj.hostname ?? urlObj.host;
Copy link
Contributor

@Lemonexe Lemonexe Jan 14, 2025

Choose a reason for hiding this comment

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

FYI here you can see difference between hostname and host https://developer.mozilla.org/en-US/docs/Web/API/Location
I'd only use hostname (w/o port), so the condition is broader = more restrictive

Also, both are typed as string, so I expect the ?? to be useless, maybe you meant || ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🏃‍♀️ In progress
Development

Successfully merging this pull request may close these issues.

Filter requests in main process and block not allowed domains
2 participants