Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library oauth2; | 5 library oauth2; |
| 6 | 6 |
| 7 import 'dart:io'; | 7 import 'dart:io'; |
| 8 import 'dart:uri'; | 8 import 'dart:uri'; |
| 9 | 9 |
| 10 // TODO(nweiz): Make this a "package:" URL, or something nicer than this. | 10 // TODO(nweiz): Make this a "package:" URL, or something nicer than this. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 completer.completeException(e, stackTrace); | 71 completer.completeException(e, stackTrace); |
| 72 } | 72 } |
| 73 }); | 73 }); |
| 74 return completer.future; | 74 return completer.future; |
| 75 }); | 75 }); |
| 76 } | 76 } |
| 77 | 77 |
| 78 /// Gets a new OAuth2 client. If saved credentials are available, those are | 78 /// Gets a new OAuth2 client. If saved credentials are available, those are |
| 79 /// used; otherwise, the user is prompted to authorize the pub client. | 79 /// used; otherwise, the user is prompted to authorize the pub client. |
| 80 Future<Client> _getClient(SystemCache cache) { | 80 Future<Client> _getClient(SystemCache cache) { |
| 81 var httpClient = new CurlClient(); | |
| 82 | |
| 83 return _loadCredentials(cache).chain((credentials) { | 81 return _loadCredentials(cache).chain((credentials) { |
| 84 if (credentials != null) { | 82 if (credentials == null) return _authorize(); |
| 85 return new Future.immediate(new Client( | 83 return new Future.immediate(new Client( |
|
Bob Nystrom
2012/11/28 19:35:41
Can't wait until Future unifies chain/transform...
nweiz
2012/11/28 19:42:14
Indeed.
| |
| 86 _identifier, _secret, credentials, httpClient: httpClient)); | 84 _identifier, _secret, credentials, httpClient: new CurlClient())); |
| 87 } | |
| 88 | |
| 89 // Allow the tests to inject their own token endpoint URL. | |
| 90 var tokenEndpoint = Platform.environment['_PUB_TEST_TOKEN_ENDPOINT']; | |
| 91 if (tokenEndpoint != null) { | |
| 92 tokenEndpoint = new Uri.fromString(tokenEndpoint); | |
| 93 } else { | |
| 94 tokenEndpoint = _tokenEndpoint; | |
| 95 } | |
| 96 | |
| 97 var grant = new AuthorizationCodeGrant( | |
| 98 _identifier, | |
| 99 _secret, | |
| 100 _authorizationEndpoint, | |
| 101 tokenEndpoint, | |
| 102 httpClient: httpClient); | |
| 103 | |
| 104 // TODO(nweiz): spin up a server on localhost and redirect the user there so | |
| 105 // they don't have to copy/paste the authorization code. See issue 6951. | |
| 106 var authUrl = grant.getAuthorizationUrl( | |
| 107 new Uri.fromString('urn:ietf:wg:oauth:2.0:oob'), scopes: _scopes); | |
| 108 | |
| 109 stdout.writeString( | |
| 110 'Pub needs your authorization to upload packages on your behalf.\n' | |
| 111 'Go to $authUrl\n' | |
| 112 'Then click "Allow access" and paste the code below:\n' | |
| 113 '> '); | |
| 114 return readLine().chain(grant.handleAuthorizationCode); | |
| 115 }).chain((client) { | 85 }).chain((client) { |
| 116 return _saveCredentials(cache, client.credentials).transform((_) => client); | 86 return _saveCredentials(cache, client.credentials).transform((_) => client); |
| 117 }); | 87 }); |
| 118 } | 88 } |
| 119 | 89 |
| 120 /// Loads the user's OAuth2 credentials from the in-memory cache or the | 90 /// Loads the user's OAuth2 credentials from the in-memory cache or the |
| 121 /// filesystem if possible. If the credentials can't be loaded for any reason, | 91 /// filesystem if possible. If the credentials can't be loaded for any reason, |
| 122 /// the returned [Future] will complete to null. | 92 /// the returned [Future] will complete to null. |
| 123 Future<Credentials> _loadCredentials(SystemCache cache) { | 93 Future<Credentials> _loadCredentials(SystemCache cache) { |
| 124 if (_credentials != null) return new Future.immediate(_credentials); | 94 if (_credentials != null) return new Future.immediate(_credentials); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 148 Future _saveCredentials(SystemCache cache, Credentials credentials) { | 118 Future _saveCredentials(SystemCache cache, Credentials credentials) { |
| 149 _credentials = credentials; | 119 _credentials = credentials; |
| 150 var credentialsFile = _credentialsFile(cache); | 120 var credentialsFile = _credentialsFile(cache); |
| 151 return ensureDir(dirname(credentialsFile)).chain((_) => | 121 return ensureDir(dirname(credentialsFile)).chain((_) => |
| 152 writeTextFile(credentialsFile, credentials.toJson())); | 122 writeTextFile(credentialsFile, credentials.toJson())); |
| 153 } | 123 } |
| 154 | 124 |
| 155 /// The path to the file in which the user's OAuth2 credentials are stored. | 125 /// The path to the file in which the user's OAuth2 credentials are stored. |
| 156 String _credentialsFile(SystemCache cache) => | 126 String _credentialsFile(SystemCache cache) => |
| 157 join(cache.rootDir, 'credentials.json'); | 127 join(cache.rootDir, 'credentials.json'); |
| 128 | |
| 129 /// Gets the user to authorize pub as a client of pub.dartlang.org via oauth2. | |
| 130 /// Returns a Future that will complete to a fully-authorized [Client]. | |
| 131 Future<Client> _authorize() { | |
| 132 // Allow the tests to inject their own token endpoint URL. | |
| 133 var tokenEndpoint = Platform.environment['_PUB_TEST_TOKEN_ENDPOINT']; | |
| 134 if (tokenEndpoint != null) { | |
| 135 tokenEndpoint = new Uri.fromString(tokenEndpoint); | |
| 136 } else { | |
| 137 tokenEndpoint = _tokenEndpoint; | |
| 138 } | |
| 139 | |
| 140 var grant = new AuthorizationCodeGrant( | |
| 141 _identifier, | |
| 142 _secret, | |
| 143 _authorizationEndpoint, | |
| 144 tokenEndpoint, | |
| 145 httpClient: new CurlClient()); | |
| 146 | |
| 147 // Spin up a one-shot HTTP server to receive the authorization code from the | |
| 148 // Google OAuth2 server via redirect. This server will close itself as soon as | |
| 149 // the code is received. | |
| 150 var completer = new Completer(); | |
| 151 var server = new HttpServer(); | |
| 152 server.addRequestHandler((request) => request.path == "/", (request, response) { | |
|
Bob Nystrom
2012/11/28 19:35:41
Long line.
nweiz
2012/11/28 19:42:14
Done.
| |
| 153 chainToCompleter(new Future.immediate(null).chain((_) { | |
| 154 print('Authorization received, processing...'); | |
| 155 var queryString = request.queryString; | |
| 156 if (queryString == null) queryString = ''; | |
| 157 response.statusCode = 302; | |
| 158 response.headers.set('location', 'http://pub.dartlang.org/authorized'); | |
| 159 response.outputStream.close(); | |
| 160 server.close(); | |
| 161 return grant.handleAuthorizationResponse(queryToMap(queryString)); | |
| 162 }), completer); | |
| 163 }); | |
| 164 server.listen('127.0.0.1', 0); | |
| 165 | |
| 166 var authUrl = grant.getAuthorizationUrl( | |
| 167 new Uri.fromString('http://localhost:${server.port}'), scopes: _scopes); | |
| 168 | |
| 169 print('Pub needs your authorization to upload packages on your behalf.\n' | |
| 170 'Go to $authUrl\n' | |
|
Bob Nystrom
2012/11/28 19:35:41
"In a web browser, go to"?
nweiz
2012/11/28 19:42:14
Done.
| |
| 171 'Then click "Allow access".\n\n' | |
| 172 'Waiting for your authorization...'); | |
| 173 | |
| 174 return completer.future.transform((client) { | |
| 175 print('Successfully authorized.\n'); | |
| 176 return client; | |
| 177 }); | |
| 178 } | |
| OLD | NEW |