Skip to content

[MV3 Dart Debug Extension] Fix authentication error #1916

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

Merged
merged 14 commits into from
Feb 1, 2023
102 changes: 60 additions & 42 deletions dwds/debug_extension_mv3/web/background.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'dart:async';
import 'dart:html';

import 'package:dwds/data/debug_info.dart';
import 'package:dwds/data/extension_request.dart';
import 'package:js/js.dart';

import 'data_types.dart';
Expand All @@ -23,8 +22,6 @@ import 'storage.dart';
import 'utils.dart';
import 'web_api.dart';

const _authSuccessResponse = 'Dart Debug Authentication Success!';

void main() {
_registerListeners();
}
Expand Down Expand Up @@ -63,59 +60,66 @@ void _registerListeners() {
));
}

Future<void> _startDebugSession(int tabId, {required Trigger trigger}) async {
final debugInfo = await _fetchDebugInfo(tabId);
final extensionUrl = debugInfo?.extensionUrl;
if (extensionUrl == null) {
_showWarningNotification('Can\'t debug Dart app. Extension URL not found.');
sendConnectFailureMessage(
ConnectFailureReason.noDartApp,
dartAppTabId: tabId,
);
return;
}
final isAuthenticated = await _authenticateUser(extensionUrl, tabId);
if (!isAuthenticated) {
sendConnectFailureMessage(
ConnectFailureReason.authentication,
dartAppTabId: tabId,
);
return;
}
Future<void> _startDebugSession(
int tabId, {
required Trigger trigger,
}) async {
final isAuthenticated = await _authenticateUser(tabId);
if (!isAuthenticated) return;

maybeCreateLifelinePort(tabId);
attachDebugger(tabId, trigger: trigger);
}

Future<bool> _authenticateUser(String extensionUrl, int tabId) async {
final authUrl = _constructAuthUrl(extensionUrl).toString();
final response = await fetchRequest(authUrl);
final responseBody = response.body ?? '';
if (!responseBody.contains(_authSuccessResponse)) {
debugError('Not authenticated: ${response.status} / $responseBody',
verbose: true);
_showWarningNotification('Please re-authenticate and try again.');
await createTab(authUrl, inNewWindow: false);
Future<bool> _authenticateUser(int tabId) async {
final isAlreadyAuthenticated = await _fetchIsAuthenticated(tabId);
if (isAlreadyAuthenticated) return true;
final debugInfo = await _fetchDebugInfo(tabId);
final authUrl = debugInfo?.authUrl;
if (authUrl == null) {
_showWarningNotification('Cannot authenticate user.');
return false;
}
return true;
}

Uri _constructAuthUrl(String extensionUrl) {
final authUri = Uri.parse(extensionUrl).replace(path: authenticationPath);
if (authUri.scheme == 'ws') {
return authUri.replace(scheme: 'http');
}
if (authUri.scheme == 'wss') {
return authUri.replace(scheme: 'https');
final isAuthenticated = await _sendAuthRequest(authUrl);
if (isAuthenticated) {
await setStorageObject<String>(
type: StorageObject.isAuthenticated,
value: '$isAuthenticated',
tabId: tabId,
);
} else {
sendConnectFailureMessage(
ConnectFailureReason.authentication,
dartAppTabId: tabId,
);
await createTab(authUrl, inNewWindow: false);
}
return authUri;
return isAuthenticated;
}

void _handleRuntimeMessages(
dynamic jsRequest, MessageSender sender, Function sendResponse) async {
if (jsRequest is! String) return;

interceptMessage<String>(
message: jsRequest,
expectedType: MessageType.isAuthenticated,
expectedSender: Script.detector,
expectedRecipient: Script.background,
messageHandler: (String isAuthenticated) async {
final dartTab = sender.tab;
if (dartTab == null) {
debugWarn('Received auth info but tab is missing.');
return;
}
// Save the authentication info in storage:
await setStorageObject<String>(
type: StorageObject.isAuthenticated,
value: isAuthenticated,
tabId: dartTab.id,
);
});

interceptMessage<DebugInfo>(
message: jsRequest,
expectedType: MessageType.debugInfo,
Expand Down Expand Up @@ -194,6 +198,20 @@ Future<DebugInfo?> _fetchDebugInfo(int tabId) {
);
}

Future<bool> _fetchIsAuthenticated(int tabId) async {
final authenticated = await fetchStorageObject<String>(
type: StorageObject.isAuthenticated,
tabId: tabId,
);
return authenticated == 'true';
}

Future<bool> _sendAuthRequest(String authUrl) async {
final response = await fetchRequest(authUrl);
final responseBody = response.body ?? '';
return responseBody.contains('Dart Debug Authentication Success!');
}

void _showWarningNotification(String message) {
chrome.notifications.create(
/*notificationId*/ null,
Expand Down
2 changes: 1 addition & 1 deletion dwds/debug_extension_mv3/web/data_serializers.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 21 additions & 6 deletions dwds/debug_extension_mv3/web/data_types.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions dwds/debug_extension_mv3/web/detector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
@JS()
library detector;

import 'dart:convert';
import 'dart:html';
import 'dart:js_util';

import 'package:dwds/data/debug_info.dart';
import 'package:js/js.dart';

import 'chrome_api.dart';
import 'data_serializers.dart';
import 'logger.dart';
import 'messaging.dart';

Expand All @@ -19,6 +23,7 @@ void main() {

void _registerListeners() {
document.addEventListener('dart-app-ready', _onDartAppReadyEvent);
document.addEventListener('dart-auth-response', _onDartAuthEvent);
}

void _onDartAppReadyEvent(Event event) {
Expand All @@ -32,9 +37,19 @@ void _onDartAppReadyEvent(Event event) {
type: MessageType.debugInfo,
body: debugInfo,
);
_sendAuthRequest(debugInfo);
}
}

void _onDartAuthEvent(Event event) {
final isAuthenticated = getProperty(event, 'detail') as String?;
if (isAuthenticated == null) return;
_sendMessageToBackgroundScript(
type: MessageType.isAuthenticated,
body: isAuthenticated,
);
}

// TODO(elliette): Remove once DWDS 17.0.0 is in Flutter stable. If we are on an
// older version of DWDS, then the debug info is not sent along with the ready
// event. Therefore we must read it from the Window object, which is slower.
Expand All @@ -57,3 +72,12 @@ void _sendMessageToBackgroundScript({
recipient: Script.background,
);
}

void _sendAuthRequest(String debugInfoJson) {
final debugInfo =
serializers.deserialize(jsonDecode(debugInfoJson)) as DebugInfo?;
final appOrigin = debugInfo?.appOrigin;
if (appOrigin != null) {
window.postMessage('dart-auth-request', appOrigin);
}
}
9 changes: 7 additions & 2 deletions dwds/debug_extension_mv3/web/messaging.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum Script {
}

enum MessageType {
isAuthenticated,
connectFailure,
debugInfo,
debugStateChange,
Expand Down Expand Up @@ -87,8 +88,12 @@ void interceptMessage<T>({
decodedMessage.from != expectedSender) {
return;
}
messageHandler(
serializers.deserialize(jsonDecode(decodedMessage.body)) as T);
if (T == String) {
messageHandler(decodedMessage.body as T);
} else {
messageHandler(
serializers.deserialize(jsonDecode(decodedMessage.body)) as T);
}
} catch (error) {
debugError(
'Error intercepting $expectedType from $expectedSender to $expectedRecipient: $error');
Expand Down
5 changes: 4 additions & 1 deletion dwds/debug_extension_mv3/web/storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ enum StorageObject {
debugInfo,
devToolsOpener,
devToolsUri,
encodedUri;
encodedUri,
isAuthenticated;

Persistance get persistance {
switch (this) {
Expand All @@ -31,6 +32,8 @@ enum StorageObject {
return Persistance.sessionOnly;
case StorageObject.encodedUri:
return Persistance.sessionOnly;
case StorageObject.isAuthenticated:
return Persistance.sessionOnly;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions dwds/lib/data/debug_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ abstract class DebugInfo implements Built<DebugInfo, DebugInfoBuilder> {
String? get appInstanceId;
String? get appOrigin;
String? get appUrl;
String? get authUrl;
String? get dwdsVersion;
String? get extensionUrl;
bool? get isInternalBuild;
Expand Down
Loading