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