blob: 645d9cb49dbf46b54991a9d58545f86ae05dd5e4 [file] [log] [blame]
import 'dart:async';
import 'package:fidl_fuchsia_auth/fidl_async.dart';
import 'package:fidl_fuchsia_sys/fidl_async.dart';
import 'package:fidl_fuchsia_ui_views/fidl_async.dart';
import 'package:fidl/fidl.dart';
import 'package:flutter/material.dart';
import 'package:fuchsia_inspect/inspect.dart' as inspect;
import 'package:fuchsia_logger/logger.dart';
import 'package:fuchsia_scenic_flutter/child_view.dart' show ChildView;
import 'package:fuchsia_scenic_flutter/child_view_connection.dart'
show ChildViewConnection;
import 'package:fuchsia_services/services.dart';
import 'package:lib.widgets/model.dart';
const String testerUrl = '/system/test/google_oauth_demo';
const String userId = 'test_user';
const String userProfileId = 'test_user_profile';
const String googleAuthProviderType = 'Google';
const String googleAuthProviderUrl =
'fuchsia-pkg://fuchsia.com/google_auth_provider#meta/google_auth_provider.cmx';
const List<String> accessTokenScopes = [
'https://www.googleapis.com/auth/plus.login'
];
const String glifFlag = 'glif';
const String dedicatedEndpointFlag = 'dedicated-endpoint';
const String authStatusField = 'auth-status';
const String successAuthStatus = 'success';
const String failureAuthStatus = 'failure';
const String unknownAuthStatus = 'unknown';
const AppConfig googleAppConfig = AppConfig(
clientId: null,
clientSecret: null,
authProviderType: googleAuthProviderType);
/// Thin app used for invoking token manager
void main(List<String> args) {
setupLogger();
final model = GoogleLoginTesterModel(inspect.Inspect().root);
final app = ScopedModel(
model: model,
child: ServiceTesterWidget(),
);
// A hack to run the authorize flow asynchronously on startup.
model.authorizeFlow();
runApp(MaterialApp(
color: Colors.white,
home: Material(type: MaterialType.transparency, child: app)));
}
class GoogleLoginTesterModel extends Model {
final TokenManagerFactoryProxy tokenManagerFactory =
TokenManagerFactoryProxy();
final TokenManagerProxy tokenManager = TokenManagerProxy();
final ComponentControllerProxy controller = ComponentControllerProxy();
// Inspect node used to report if the authentication flow has succeeded.
final inspect.Node _inspectNode;
ChildViewConnection childViewConnection;
String userProfileId;
GoogleLoginTesterModel(this._inspectNode) {
_inspectNode.stringProperty(authStatusField).setValue(unknownAuthStatus);
}
Future<void> authorize() async {
final response =
await tokenManager.authorize(googleAppConfig, null, [], '', '');
final status = response.status;
if (status != Status.ok) {
throw ServiceTesterException('Token manager authorize failed');
}
final info = response.userProfileInfo;
userProfileId = info.id;
}
List<AuthProviderConfig> _buildAuthProviderConfigs() {
return [
AuthProviderConfig(
authProviderType: googleAuthProviderType,
url: googleAuthProviderUrl,
params: <String>[])
];
}
Future<void> connectToTokenManager() async {
final incoming = Incoming();
final LaunchInfo launchInfo = LaunchInfo(
url:
'fuchsia-pkg://fuchsia.com/token_manager_factory#meta/token_manager_factory.cmx',
directoryRequest: incoming.request().passChannel());
// launch token manager factory using the launcher service.
final launcherProxy = LauncherProxy();
StartupContext.fromStartupInfo().incoming.connectToService(launcherProxy);
await launcherProxy.createComponent(launchInfo, controller.ctrl.request());
launcherProxy.ctrl.close();
incoming.connectToService(tokenManagerFactory);
await tokenManagerFactory.getTokenManager(
userId,
testerUrl,
_buildAuthProviderConfigs(),
AuthenticationContextProviderBinding()
.wrap(_AuthenticationContextProviderImpl(this)),
tokenManager.ctrl.request());
}
Future<void> getAccessToken() async {
final response = await tokenManager.getAccessToken(
googleAppConfig, userProfileId, accessTokenScopes);
final status = response.status;
if (status != Status.ok) {
throw ServiceTesterException('Token manager getAccessToken failed');
}
}
Future<void> authorizeFlow() async {
try {
await connectToTokenManager();
await authorize();
await getAccessToken();
_inspectNode.stringProperty(authStatusField).setValue(successAuthStatus);
} on ServiceTesterException {
_inspectNode.stringProperty(authStatusField).setValue(failureAuthStatus);
}
notifyListeners();
}
}
class _AuthenticationContextProviderImpl extends AuthenticationContextProvider {
final _AuthenticationUiContextImpl _contextImpl;
_AuthenticationContextProviderImpl(GoogleLoginTesterModel model)
: _contextImpl = _AuthenticationUiContextImpl(model);
@override
Future<void> getAuthenticationUiContext(
InterfaceRequest<AuthenticationUiContext> request) async {
AuthenticationUiContextBinding().bind(_contextImpl, request);
}
}
class _AuthenticationUiContextImpl extends AuthenticationUiContext {
final GoogleLoginTesterModel _model;
_AuthenticationUiContextImpl(this._model);
@override
Future<void> startOverlay(ViewHolderToken viewHolderToken) async {
var viewConnection = ChildViewConnection(
viewHolderToken,
onAvailable: (ChildViewConnection connection) {
connection.requestFocus();
_model.notifyListeners();
},
onUnavailable: (ChildViewConnection connection) {
stopOverlay();
},
);
_model
..childViewConnection = viewConnection
..notifyListeners();
}
@override
Future<Null> stopOverlay() async {
_model
..childViewConnection = null
..notifyListeners();
}
}
class ServiceTesterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) =>
ScopedModelDescendant<GoogleLoginTesterModel>(
builder: _buildServiceTester);
Widget _buildServiceTester(
BuildContext context, Widget child, GoogleLoginTesterModel model) {
return Container(
child: model.childViewConnection != null
? ChildView(connection: model.childViewConnection)
: Placeholder());
}
}
class ServiceTesterException implements Exception {
final String message;
ServiceTesterException(this.message);
@override
String toString() {
return 'ServiceTesterException: $message';
}
}