pick http for .onion by default
This commit is contained in:
@@ -821,6 +821,13 @@
|
||||
"enforceOnStartup": true,
|
||||
"locked": true
|
||||
},
|
||||
"dom.security.https_only_mode.upgrade_onion": {
|
||||
"value": false,
|
||||
"title": "Keep .onion sites on HTTP",
|
||||
"description": "Exempts .onion hosts from HTTPS-Only/HTTPS-First upgrades. Onion services are reached over an encrypted, self-authenticating Tor circuit, so HTTP carries no clearnet exposure and most onion sites are HTTP-only.",
|
||||
"enforceOnStartup": true,
|
||||
"locked": true
|
||||
},
|
||||
"security.mixed_content.upgrade_display_content": {
|
||||
"value": true,
|
||||
"title": "Upgrade mixed display content to HTTPS",
|
||||
|
||||
@@ -27,6 +27,7 @@ enum NavigationReason {
|
||||
explicitScheme,
|
||||
schemelessHost,
|
||||
localhost,
|
||||
onionHost,
|
||||
ipLiteral,
|
||||
aboutLike,
|
||||
}
|
||||
@@ -145,6 +146,13 @@ InputClassification classifyAddressBarInput(
|
||||
);
|
||||
}
|
||||
|
||||
if (isOnionHost(schemelessUri.host)) {
|
||||
return InputClassification.navigate(
|
||||
schemelessUri,
|
||||
NavigationReason.onionHost,
|
||||
);
|
||||
}
|
||||
|
||||
if (InternetAddress.tryParse(schemelessUri.host) != null) {
|
||||
return InputClassification.navigate(
|
||||
schemelessUri,
|
||||
|
||||
@@ -114,6 +114,12 @@ bool isValidHostCandidate(String hostCandidate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isOnionHost(String host) {
|
||||
// RFC 7686: ".onion" must be the final label, never a substring. The leading
|
||||
// dot requirement rejects bare "onion", "notonion.com" and "onion.evil.com".
|
||||
return host.toLowerCase().endsWith('.onion');
|
||||
}
|
||||
|
||||
bool looksLikeHostExpression(String input) {
|
||||
return input.contains('.') ||
|
||||
input.contains(':') ||
|
||||
@@ -183,7 +189,13 @@ Uri? parseSchemelessWebHost(
|
||||
return null;
|
||||
}
|
||||
|
||||
final scheme = probeUri.host.toLowerCase() == 'localhost' ? 'http' : 'https';
|
||||
// Onion services are self-authenticating and reached over an encrypted Tor
|
||||
// circuit, so http carries no clearnet exposure; default them to http like
|
||||
// localhost (see Tor Browser's HTTPS-Only exemption for .onion).
|
||||
final lowerHost = probeUri.host.toLowerCase();
|
||||
final scheme = (lowerHost == 'localhost' || isOnionHost(lowerHost))
|
||||
? 'http'
|
||||
: 'https';
|
||||
if (allowedSchemes != null && !allowedSchemes.contains(scheme)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,49 @@ void main() {
|
||||
expect(navigation.uri.toString(), 'https://weblibre.eu');
|
||||
});
|
||||
|
||||
test('navigates onion host over http', () {
|
||||
final result = classifyAddressBarInput(
|
||||
'duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/path',
|
||||
);
|
||||
|
||||
expect(result, isA<NavigateInputClassification>());
|
||||
final navigation = result as NavigateInputClassification;
|
||||
expect(navigation.reason, NavigationReason.onionHost);
|
||||
expect(
|
||||
navigation.uri.toString(),
|
||||
'http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/path',
|
||||
);
|
||||
});
|
||||
|
||||
test('keeps explicit https on onion host', () {
|
||||
final result = classifyAddressBarInput(
|
||||
'https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion',
|
||||
);
|
||||
|
||||
expect(result, isA<NavigateInputClassification>());
|
||||
final navigation = result as NavigateInputClassification;
|
||||
expect(navigation.reason, NavigationReason.explicitScheme);
|
||||
expect(navigation.uri.scheme, 'https');
|
||||
});
|
||||
|
||||
test('does not http-default a non-onion lookalike host', () {
|
||||
final result = classifyAddressBarInput('notonion.com');
|
||||
|
||||
expect(result, isA<NavigateInputClassification>());
|
||||
final navigation = result as NavigateInputClassification;
|
||||
expect(navigation.reason, NavigationReason.schemelessHost);
|
||||
expect(navigation.uri.toString(), 'https://notonion.com');
|
||||
});
|
||||
|
||||
test('does not http-default onion as a non-final label', () {
|
||||
final result = classifyAddressBarInput('onion.example.com');
|
||||
|
||||
expect(result, isA<NavigateInputClassification>());
|
||||
final navigation = result as NavigateInputClassification;
|
||||
expect(navigation.reason, NavigationReason.schemelessHost);
|
||||
expect(navigation.uri.toString(), 'https://onion.example.com');
|
||||
});
|
||||
|
||||
test('navigates localhost over http', () {
|
||||
final result = classifyAddressBarInput('localhost:8080');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user