| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if !defined(__has_feature) || !__has_feature(objc_arc) | 5 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 6 #error "This file requires ARC support." | 6 #error "This file requires ARC support." |
| 7 #endif | 7 #endif |
| 8 | 8 |
| 9 #import "remoting/client/ios/facade/remoting_service.h" | 9 #import "remoting/client/ios/facade/remoting_service.h" |
| 10 | 10 |
| 11 #import <Foundation/Foundation.h> | 11 #import <Foundation/Foundation.h> |
| 12 #import <Security/Security.h> |
| 12 | 13 |
| 13 #import "base/mac/bind_objc_block.h" | 14 #import "base/mac/bind_objc_block.h" |
| 15 #import "remoting/client/ios/domain/host_info.h" |
| 16 #import "remoting/client/ios/domain/user_info.h" |
| 17 #import "remoting/client/ios/facade/host_info.h" |
| 18 #import "remoting/client/ios/facade/host_list_fetcher.h" |
| 19 #import "remoting/client/ios/facade/ios_client_runtime_delegate.h" |
| 20 #import "remoting/client/ios/facade/remoting_authentication.h" |
| 21 #import "remoting/client/ios/facade/remoting_service.h" |
| 22 #import "remoting/client/ios/keychain_wrapper.h" |
| 14 | 23 |
| 15 #include "base/logging.h" | 24 #include "base/logging.h" |
| 16 #include "base/strings/sys_string_conversions.h" | 25 #include "base/strings/sys_string_conversions.h" |
| 17 #include "net/url_request/url_request_context_getter.h" | 26 #include "net/url_request/url_request_context_getter.h" |
| 18 #include "remoting/base/oauth_token_getter.h" | 27 #include "remoting/base/oauth_token_getter.h" |
| 19 #include "remoting/base/oauth_token_getter_impl.h" | 28 #include "remoting/base/oauth_token_getter_impl.h" |
| 20 #include "remoting/client/ios/facade/host_info.h" | |
| 21 #include "remoting/client/ios/facade/host_list_fetcher.h" | |
| 22 #include "remoting/client/ios/facade/ios_client_runtime_delegate.h" | |
| 23 | 29 |
| 24 const char kOauthRedirectUrl[] = | 30 static NSString* const kCRDAuthenticatedUserEmailKey = |
| 25 "https://chromoting-oauth.talkgadget." | 31 @"kCRDAuthenticatedUserEmailKey"; |
| 26 "google.com/talkgadget/oauth/chrome-remote-desktop/dev"; | |
| 27 | 32 |
| 28 std::unique_ptr<remoting::OAuthTokenGetter> | 33 NSString* const kHostsDidUpdate = @"kHostsDidUpdate"; |
| 29 CreateOAuthTokenGetterWithAuthorizationCode( | |
| 30 const std::string& auth_code, | |
| 31 const remoting::OAuthTokenGetter::CredentialsUpdatedCallback& | |
| 32 on_credentials_update) { | |
| 33 std::unique_ptr<remoting::OAuthTokenGetter::OAuthIntermediateCredentials> | |
| 34 oauth_credentials( | |
| 35 new remoting::OAuthTokenGetter::OAuthIntermediateCredentials( | |
| 36 auth_code, /*is_service_account=*/false)); | |
| 37 oauth_credentials->oauth_redirect_uri = kOauthRedirectUrl; | |
| 38 | 34 |
| 39 std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter( | 35 NSString* const kUserDidUpdate = @"kUserDidUpdate"; |
| 40 new remoting::OAuthTokenGetterImpl( | 36 NSString* const kUserInfo = @"kUserInfo"; |
| 41 std::move(oauth_credentials), on_credentials_update, | |
| 42 [[RemotingService SharedInstance] runtime]->url_requester(), | |
| 43 /*auto_refresh=*/true)); | |
| 44 return oauth_tokenGetter; | |
| 45 } | |
| 46 | 37 |
| 47 std::unique_ptr<remoting::OAuthTokenGetter> CreateOAuthTokenWithRefreshToken( | 38 @interface RemotingService ()<RemotingAuthenticationDelegate> { |
| 48 const std::string& refresh_token, | |
| 49 const std::string& email) { | |
| 50 std::unique_ptr<remoting::OAuthTokenGetter::OAuthAuthorizationCredentials> | |
| 51 oauth_credentials( | |
| 52 new remoting::OAuthTokenGetter::OAuthAuthorizationCredentials( | |
| 53 email, refresh_token, /*is_service_account=*/false)); | |
| 54 | |
| 55 std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter( | |
| 56 new remoting::OAuthTokenGetterImpl( | |
| 57 std::move(oauth_credentials), | |
| 58 [[RemotingService SharedInstance] runtime]->url_requester(), | |
| 59 /*auto_refresh=*/true)); | |
| 60 return oauth_tokenGetter; | |
| 61 } | |
| 62 | |
| 63 @interface RemotingService () { | |
| 64 std::unique_ptr<remoting::OAuthTokenGetter> _tokenGetter; | 39 std::unique_ptr<remoting::OAuthTokenGetter> _tokenGetter; |
| 65 UserInfo* _user; | |
| 66 NSArray<HostInfo*>* _hosts; | |
| 67 id<RemotingAuthenticationDelegate> _authDelegate; | |
| 68 id<RemotingHostListDelegate> _hostListDelegate; | |
| 69 remoting::HostListFetcher* _hostListFetcher; | 40 remoting::HostListFetcher* _hostListFetcher; |
| 70 remoting::IosClientRuntimeDelegate* _clientRuntimeDelegate; | 41 remoting::IosClientRuntimeDelegate* _clientRuntimeDelegate; |
| 71 } | 42 } |
| 72 | |
| 73 @end | 43 @end |
| 74 | 44 |
| 75 // | |
| 76 // RemodingService will act as the facade to the C++ layer that has not been | |
| 77 // implemented/integrated yet. | |
| 78 // TODO(nicholss): Implement/Integrate this class. At the moment it is being | |
| 79 // used to generate fake data to implement the UI of the app. | |
| 80 // Update: Half implemented now. User is still fake, but now real hosts lists. | |
| 81 // | |
| 82 @implementation RemotingService | 45 @implementation RemotingService |
| 83 | 46 |
| 47 @synthesize authentication = _authentication; |
| 48 @synthesize hosts = _hosts; |
| 49 |
| 84 // RemotingService is a singleton. | 50 // RemotingService is a singleton. |
| 85 + (RemotingService*)SharedInstance { | 51 + (RemotingService*)SharedInstance { |
| 86 static RemotingService* sharedInstance = nil; | 52 static RemotingService* sharedInstance = nil; |
| 87 static dispatch_once_t guard; | 53 static dispatch_once_t guard; |
| 88 dispatch_once(&guard, ^{ | 54 dispatch_once(&guard, ^{ |
| 89 sharedInstance = [[RemotingService alloc] init]; | 55 sharedInstance = [[RemotingService alloc] init]; |
| 90 }); | 56 }); |
| 91 return sharedInstance; | 57 return sharedInstance; |
| 92 } | 58 } |
| 93 | 59 |
| 94 - (instancetype)init { | 60 - (instancetype)init { |
| 95 self = [super init]; | 61 self = [super init]; |
| 96 if (self) { | 62 if (self) { |
| 97 _user = nil; | 63 _authentication = [[RemotingAuthentication alloc] init]; |
| 64 _authentication.delegate = self; |
| 98 _hosts = nil; | 65 _hosts = nil; |
| 99 _hostListFetcher = new remoting::HostListFetcher( | 66 _hostListFetcher = nil; |
| 100 remoting::ChromotingClientRuntime::GetInstance()->url_requester()); | |
| 101 // TODO(nicholss): This might need a pointer back to the service. | 67 // TODO(nicholss): This might need a pointer back to the service. |
| 102 _clientRuntimeDelegate = | 68 _clientRuntimeDelegate = |
| 103 new remoting::IosClientRuntimeDelegate(); | 69 new remoting::IosClientRuntimeDelegate(); |
| 104 [self runtime]->SetDelegate(_clientRuntimeDelegate); | 70 [self runtime]->SetDelegate(_clientRuntimeDelegate); |
| 105 } | 71 } |
| 106 return self; | 72 return self; |
| 107 } | 73 } |
| 108 | 74 |
| 109 #pragma mark - RemotingService Implementation | 75 #pragma mark - RemotingService Implementation |
| 110 | 76 |
| 111 // TODO(nicholss): isAuthenticated needs to just kick off a request to | 77 - (void)startHostListFetchWith:(NSString*)accessToken { |
| 112 // authenticate a user. and more than one controller might want to be a delegate | 78 if (!_hostListFetcher) { |
| 113 // for this info so need to change this to be more of the registration types. | 79 _hostListFetcher = new remoting::HostListFetcher( |
| 114 // The remoting_service might also want to be registered for authentication | 80 remoting::ChromotingClientRuntime::GetInstance()->url_requester()); |
| 115 // changes and it can update it's cache as it needs. | |
| 116 | |
| 117 - (void)setAuthenticationDelegate:(id<RemotingAuthenticationDelegate>)delegate { | |
| 118 _authDelegate = delegate; | |
| 119 if (_authDelegate) { | |
| 120 [_authDelegate nowAuthenticated:[self isAuthenticated]]; | |
| 121 } | 81 } |
| 122 if (!_user && _tokenGetter) { | 82 _hostListFetcher->RetrieveHostlist( |
| 123 _tokenGetter->CallWithToken(base::BindBlockArc( | 83 base::SysNSStringToUTF8(accessToken), |
| 124 ^(remoting::OAuthTokenGetter::Status status, | 84 base::BindBlockArc(^(const std::vector<remoting::HostInfo>& hostlist) { |
| 125 const std::string& user_email, const std::string& access_token) { | 85 NSMutableArray<HostInfo*>* hosts = |
| 126 if (status == remoting::OAuthTokenGetter::Status::SUCCESS) { | 86 [NSMutableArray arrayWithCapacity:hostlist.size()]; |
| 127 _user = [[UserInfo alloc] init]; | 87 std::string status; |
| 128 _user.userEmail = | 88 for (const remoting::HostInfo& host_info : hostlist) { |
| 129 [NSString stringWithCString:user_email.c_str() | 89 remoting::HostStatus host_status = host_info.status; |
| 130 encoding:[NSString defaultCStringEncoding]]; | 90 switch (host_status) { |
| 131 } else { | 91 case remoting::kHostStatusOnline: |
| 132 _user = nil; | 92 status = "ONLINE"; |
| 93 break; |
| 94 case remoting::kHostStatusOffline: |
| 95 status = "OFFLINE"; |
| 96 break; |
| 97 default: |
| 98 NOTREACHED(); |
| 133 } | 99 } |
| 134 if (_authDelegate) { | 100 // TODO(nicholss): Not yet integrated: createdTime, hostVersion, |
| 135 [_authDelegate nowAuthenticated:[self isAuthenticated]]; | 101 // kind, offlineReason. Add them as the app will need this info. |
| 136 } | 102 HostInfo* host = [[HostInfo alloc] init]; |
| 137 })); | 103 host.hostId = |
| 138 } | 104 [NSString stringWithCString:host_info.host_id.c_str() |
| 105 encoding:[NSString defaultCStringEncoding]]; |
| 106 host.hostName = |
| 107 [NSString stringWithCString:host_info.host_name.c_str() |
| 108 encoding:[NSString defaultCStringEncoding]]; |
| 109 host.jabberId = |
| 110 [NSString stringWithCString:host_info.host_jid.c_str() |
| 111 encoding:[NSString defaultCStringEncoding]]; |
| 112 host.publicKey = |
| 113 [NSString stringWithCString:host_info.public_key.c_str() |
| 114 encoding:[NSString defaultCStringEncoding]]; |
| 115 host.status = |
| 116 [NSString stringWithCString:status.c_str() |
| 117 encoding:[NSString defaultCStringEncoding]]; |
| 118 [hosts addObject:host]; |
| 119 } |
| 120 _hosts = hosts; |
| 121 [self hostListUpdated]; |
| 122 })); |
| 139 } | 123 } |
| 140 | 124 |
| 141 - (BOOL)isAuthenticated { | 125 #pragma mark - Notifications |
| 142 if (_user) { | 126 |
| 143 return YES; | 127 - (void)hostListUpdated { |
| 144 } | 128 [[NSNotificationCenter defaultCenter] postNotificationName:kHostsDidUpdate |
| 145 return NO; | 129 object:self |
| 130 userInfo:nil]; |
| 146 } | 131 } |
| 147 | 132 |
| 148 - (void)startHostListFetchWith:(NSString*)accessToken { | 133 #pragma mark - RemotingAuthenticationDelegate |
| 149 NSLog(@"startHostListFetchWith : %@ %@", accessToken, _authDelegate); | |
| 150 if (_authDelegate) { | |
| 151 [_authDelegate nowAuthenticated:YES]; | |
| 152 | 134 |
| 153 _hostListFetcher->RetrieveHostlist( | 135 - (void)userDidUpdate:(UserInfo*)user { |
| 154 base::SysNSStringToUTF8(accessToken), | 136 NSDictionary* userInfo = nil; |
| 155 base::BindBlockArc(^(const std::vector<remoting::HostInfo>& hostlist) { | 137 if (user) { |
| 156 NSMutableArray<HostInfo*>* hosts = | 138 userInfo = [NSDictionary dictionaryWithObject:user forKey:kUserInfo]; |
| 157 [NSMutableArray arrayWithCapacity:hostlist.size()]; | 139 } else { |
| 158 std::string status; | 140 _hosts = nil; |
| 159 for (const remoting::HostInfo& host_info : hostlist) { | 141 [self hostListUpdated]; |
| 160 remoting::HostStatus host_status = host_info.status; | |
| 161 switch (host_status) { | |
| 162 case remoting::kHostStatusOnline: | |
| 163 status = "ONLINE"; | |
| 164 break; | |
| 165 case remoting::kHostStatusOffline: | |
| 166 status = "OFFLINE"; | |
| 167 break; | |
| 168 default: | |
| 169 NOTREACHED(); | |
| 170 } | |
| 171 // TODO(nicholss): Not yet integrated: createdTime, hostVersion, | |
| 172 // kind, offlineReason. Add them as the app will need this info. | |
| 173 HostInfo* host = [[HostInfo alloc] init]; | |
| 174 host.hostId = | |
| 175 [NSString stringWithCString:host_info.host_id.c_str() | |
| 176 encoding:[NSString defaultCStringEncoding]]; | |
| 177 host.hostName = | |
| 178 [NSString stringWithCString:host_info.host_name.c_str() | |
| 179 encoding:[NSString defaultCStringEncoding]]; | |
| 180 host.jabberId = | |
| 181 [NSString stringWithCString:host_info.host_jid.c_str() | |
| 182 encoding:[NSString defaultCStringEncoding]]; | |
| 183 host.publicKey = | |
| 184 [NSString stringWithCString:host_info.public_key.c_str() | |
| 185 encoding:[NSString defaultCStringEncoding]]; | |
| 186 host.status = | |
| 187 [NSString stringWithCString:status.c_str() | |
| 188 encoding:[NSString defaultCStringEncoding]]; | |
| 189 [hosts addObject:host]; | |
| 190 } | |
| 191 _hosts = hosts; | |
| 192 [_hostListDelegate hostListUpdated]; | |
| 193 })); | |
| 194 } | 142 } |
| 143 [[NSNotificationCenter defaultCenter] postNotificationName:kUserDidUpdate |
| 144 object:self |
| 145 userInfo:userInfo]; |
| 195 } | 146 } |
| 196 | 147 |
| 197 - (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode { | 148 #pragma mark - Properties |
| 198 _tokenGetter = CreateOAuthTokenGetterWithAuthorizationCode( | |
| 199 std::string(base::SysNSStringToUTF8(authorizationCode)), | |
| 200 base::BindBlockArc( | |
| 201 ^(const std::string& user_email, const std::string& refresh_token) { | |
| 202 // TODO(nicholss): Do something with these new creds. | |
| 203 VLOG(1) << "New Creds: " << user_email << " " << refresh_token; | |
| 204 })); | |
| 205 } | |
| 206 | 149 |
| 207 - (void)authenticateWithRefreshToken:(NSString*)refreshToken | 150 - (NSArray<HostInfo*>*)hosts { |
| 208 email:(NSString*)email { | 151 if ([_authentication.user isAuthenticated]) { |
| 209 _tokenGetter = CreateOAuthTokenWithRefreshToken( | 152 return _hosts; |
| 210 std::string(base::SysNSStringToUTF8(refreshToken)), | |
| 211 base::SysNSStringToUTF8(email)); | |
| 212 } | |
| 213 | |
| 214 - (UserInfo*)getUser { | |
| 215 if (![self isAuthenticated]) { | |
| 216 return nil; | |
| 217 } | 153 } |
| 218 | 154 return nil; |
| 219 NSMutableString* json = [[NSMutableString alloc] init]; | |
| 220 [json appendString:@"{"]; | |
| 221 [json appendString:@"\"userId\":\"AABBCC123\","]; | |
| 222 [json appendString:@"\"userFullName\":\"John Smith\","]; | |
| 223 [json appendString:@"\"userEmail\":\"john@example.com\","]; | |
| 224 [json appendString:@"}"]; | |
| 225 | |
| 226 NSMutableData* data = [NSMutableData | |
| 227 dataWithData:[[json copy] dataUsingEncoding:NSUTF8StringEncoding]]; | |
| 228 | |
| 229 UserInfo* user = [UserInfo parseListFromJSON:data]; | |
| 230 return user; | |
| 231 } | |
| 232 | |
| 233 - (void)setHostListDelegate:(id<RemotingHostListDelegate>)delegate { | |
| 234 bool attemptUpdate = (_hostListDelegate != delegate); | |
| 235 _hostListDelegate = delegate; | |
| 236 if (attemptUpdate && _hostListDelegate && _tokenGetter) { | |
| 237 // TODO(nicholss): It might be cleaner to set the delegate and then have | |
| 238 // them ask to refresh the host list rather than start this get hosts call. | |
| 239 _tokenGetter->CallWithToken(base::BindBlockArc( | |
| 240 ^(remoting::OAuthTokenGetter::Status status, | |
| 241 const std::string& user_email, const std::string& access_token) { | |
| 242 NSString* accessToken = | |
| 243 [NSString stringWithCString:access_token.c_str() | |
| 244 encoding:[NSString defaultCStringEncoding]]; | |
| 245 [self startHostListFetchWith:accessToken]; | |
| 246 })); | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 - (NSArray<HostInfo*>*)getHosts { | |
| 251 if (![self isAuthenticated]) { | |
| 252 return nil; | |
| 253 } | |
| 254 return _hosts; | |
| 255 } | 155 } |
| 256 | 156 |
| 257 - (remoting::ChromotingClientRuntime*)runtime { | 157 - (remoting::ChromotingClientRuntime*)runtime { |
| 258 return remoting::ChromotingClientRuntime::GetInstance(); | 158 return remoting::ChromotingClientRuntime::GetInstance(); |
| 259 } | 159 } |
| 260 | 160 |
| 261 - (void)callbackWithAccessToken: | 161 #pragma mark - Implementation |
| 262 (const remoting::OAuthTokenGetter::TokenCallback&)onAccessToken { | 162 |
| 263 if (_tokenGetter) { | 163 - (void)requestHostListFetch { |
| 264 _tokenGetter->CallWithToken(onAccessToken); | 164 [_authentication |
| 265 } | 165 callbackWithAccessToken:base::BindBlockArc(^( |
| 166 remoting::OAuthTokenGetter::Status status, |
| 167 const std::string& user_email, |
| 168 const std::string& access_token) { |
| 169 NSString* accessToken = |
| 170 [NSString stringWithCString:access_token.c_str() |
| 171 encoding:[NSString defaultCStringEncoding]]; |
| 172 [self startHostListFetchWith:accessToken]; |
| 173 })]; |
| 266 } | 174 } |
| 267 | 175 |
| 268 @end | 176 @end |
| OLD | NEW |