Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: utils/pub/oauth2.dart

Issue 11785028: Commit Martin's patch for pub + lib_v2. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Revise. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/pub/log.dart ('k') | utils/pub/validator.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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:async';
7 import 'dart:io'; 8 import 'dart:io';
8 import 'dart:uri'; 9 import 'dart:uri';
9 10
10 // TODO(nweiz): Make this a "package:" URL, or something nicer than this. 11 // TODO(nweiz): Make this a "package:" URL, or something nicer than this.
11 import '../../pkg/oauth2/lib/oauth2.dart'; 12 import '../../pkg/oauth2/lib/oauth2.dart';
12 import 'http.dart'; 13 import 'http.dart';
13 import 'io.dart'; 14 import 'io.dart';
14 import 'log.dart' as log; 15 import 'log.dart' as log;
15 import 'system_cache.dart'; 16 import 'system_cache.dart';
16 import 'utils.dart'; 17 import 'utils.dart';
(...skipping 29 matching lines...) Expand all
46 final _scopes = ['https://www.googleapis.com/auth/userinfo.email']; 47 final _scopes = ['https://www.googleapis.com/auth/userinfo.email'];
47 48
48 /// An in-memory cache of the user's OAuth2 credentials. This should always be 49 /// An in-memory cache of the user's OAuth2 credentials. This should always be
49 /// the same as the credentials file stored in the system cache. 50 /// the same as the credentials file stored in the system cache.
50 Credentials _credentials; 51 Credentials _credentials;
51 52
52 /// Delete the cached credentials, if they exist. 53 /// Delete the cached credentials, if they exist.
53 Future clearCredentials(SystemCache cache) { 54 Future clearCredentials(SystemCache cache) {
54 _credentials = null; 55 _credentials = null;
55 var credentialsFile = _credentialsFile(cache); 56 var credentialsFile = _credentialsFile(cache);
56 return fileExists(credentialsFile).chain((exists) { 57 return fileExists(credentialsFile).then((exists) {
57 if (exists) return deleteFile(credentialsFile); 58 if (exists) return deleteFile(credentialsFile);
58 return new Future.immediate(null); 59 return new Future.immediate(null);
59 }); 60 });
60 } 61 }
61 62
62 /// Asynchronously passes an OAuth2 [Client] to [fn], and closes the client when 63 /// Asynchronously passes an OAuth2 [Client] to [fn], and closes the client when
63 /// the [Future] returned by [fn] completes. 64 /// the [Future] returned by [fn] completes.
64 /// 65 ///
65 /// This takes care of loading and saving the client's credentials, as well as 66 /// This takes care of loading and saving the client's credentials, as well as
66 /// prompting the user for their authorization. It will also re-authorize and 67 /// prompting the user for their authorization. It will also re-authorize and
67 /// re-run [fn] if a recoverable authorization error is detected. 68 /// re-run [fn] if a recoverable authorization error is detected.
68 Future withClient(SystemCache cache, Future fn(Client client)) { 69 Future withClient(SystemCache cache, Future fn(Client client)) {
69 return _getClient(cache).chain((client) { 70 return _getClient(cache).then((client) {
70 var completer = new Completer(); 71 var completer = new Completer();
71 var future = fn(client); 72 var future = fn(client);
72 future.onComplete((_) { 73 future.whenComplete(() {
73 try { 74 try {
74 client.close(); 75 client.close();
75 // Be sure to save the credentials even when an error happens. Also be 76 // Be sure to save the credentials even when an error happens. Also be
76 // sure to pipe the exception from `future` to `completer`. 77 // sure to pipe the exception from `future` to `completer`.
77 chainToCompleter( 78 chainToCompleter(
78 _saveCredentials(cache, client.credentials).chain((_) => future), 79 _saveCredentials(cache, client.credentials).then((_) => future),
79 completer); 80 completer);
80 } catch (e, stackTrace) { 81 } catch (e, stackTrace) {
81 // onComplete will drop exceptions on the floor. We want to ensure that 82 // whenComplete will drop exceptions on the floor. We want to ensure
82 // any programming errors here don't go un-noticed. See issue 4127. 83 // that any programming errors here don't go un-noticed. See issue 4127.
83 completer.completeException(e, stackTrace); 84 completer.completeException(e, stackTrace);
84 } 85 }
85 }); 86 });
86 return completer.future; 87 return completer.future;
87 }).transformException((e) { 88 }).catchError((e) {
88 if (e is ExpirationException) { 89 if (e is ExpirationException) {
89 log.error("Pub's authorization to upload packages has expired and " 90 log.error("Pub's authorization to upload packages has expired and "
90 "can't be automatically refreshed."); 91 "can't be automatically refreshed.");
91 return withClient(cache, fn); 92 return withClient(cache, fn);
92 } else if (e is AuthorizationException) { 93 } else if (e is AuthorizationException) {
93 var message = "OAuth2 authorization failed"; 94 var message = "OAuth2 authorization failed";
94 if (e.description != null) message = "$message (${e.description})"; 95 if (e.description != null) message = "$message (${e.description})";
95 log.error("$message."); 96 log.error("$message.");
96 return clearCredentials(cache).chain((_) => withClient(cache, fn)); 97 return clearCredentials(cache).then((_) => withClient(cache, fn));
97 } else { 98 } else {
98 throw e; 99 throw e;
99 } 100 }
100 }); 101 });
101 } 102 }
102 103
103 /// Gets a new OAuth2 client. If saved credentials are available, those are 104 /// Gets a new OAuth2 client. If saved credentials are available, those are
104 /// used; otherwise, the user is prompted to authorize the pub client. 105 /// used; otherwise, the user is prompted to authorize the pub client.
105 Future<Client> _getClient(SystemCache cache) { 106 Future<Client> _getClient(SystemCache cache) {
106 return _loadCredentials(cache).chain((credentials) { 107 return _loadCredentials(cache).then((credentials) {
107 if (credentials == null) return _authorize(); 108 if (credentials == null) return _authorize();
108 return new Future.immediate(new Client( 109 return new Future.immediate(new Client(
109 _identifier, _secret, credentials, httpClient: curlClient)); 110 _identifier, _secret, credentials, httpClient: curlClient));
110 }).chain((client) { 111 }).then((client) {
111 return _saveCredentials(cache, client.credentials).then((_) => client); 112 return _saveCredentials(cache, client.credentials).then((_) => client);
112 }); 113 });
113 } 114 }
114 115
115 /// Loads the user's OAuth2 credentials from the in-memory cache or the 116 /// Loads the user's OAuth2 credentials from the in-memory cache or the
116 /// filesystem if possible. If the credentials can't be loaded for any reason, 117 /// filesystem if possible. If the credentials can't be loaded for any reason,
117 /// the returned [Future] will complete to null. 118 /// the returned [Future] will complete to null.
118 Future<Credentials> _loadCredentials(SystemCache cache) { 119 Future<Credentials> _loadCredentials(SystemCache cache) {
119 log.fine('Loading OAuth2 credentials.'); 120 log.fine('Loading OAuth2 credentials.');
120 121
121 if (_credentials != null) { 122 if (_credentials != null) {
122 log.fine('Using already-loaded credentials.'); 123 log.fine('Using already-loaded credentials.');
123 return new Future.immediate(_credentials); 124 return new Future.immediate(_credentials);
124 } 125 }
125 126
126 var path = _credentialsFile(cache); 127 var path = _credentialsFile(cache);
127 return fileExists(path).chain((credentialsExist) { 128 return fileExists(path).then((credentialsExist) {
128 if (!credentialsExist) { 129 if (!credentialsExist) {
129 log.fine('No credentials found at $path.'); 130 log.fine('No credentials found at $path.');
130 return new Future.immediate(null); 131 return new Future.immediate(null);
131 } 132 }
132 133
133 return readTextFile(_credentialsFile(cache)).then((credentialsJson) { 134 return readTextFile(_credentialsFile(cache)).then((credentialsJson) {
134 var credentials = new Credentials.fromJson(credentialsJson); 135 var credentials = new Credentials.fromJson(credentialsJson);
135 if (credentials.isExpired && !credentials.canRefresh) { 136 if (credentials.isExpired && !credentials.canRefresh) {
136 log.error("Pub's authorization to upload packages has expired and " 137 log.error("Pub's authorization to upload packages has expired and "
137 "can't be automatically refreshed."); 138 "can't be automatically refreshed.");
138 return null; // null means re-authorize 139 return null; // null means re-authorize
139 } 140 }
140 141
141 return credentials; 142 return credentials;
142 }); 143 });
143 }).transformException((e) { 144 }).catchError((e) {
144 log.error('Warning: could not load the saved OAuth2 credentials: $e\n' 145 log.error('Warning: could not load the saved OAuth2 credentials: $e\n'
145 'Obtaining new credentials...'); 146 'Obtaining new credentials...');
146 return null; // null means re-authorize 147 return null; // null means re-authorize
147 }); 148 });
148 } 149 }
149 150
150 /// Save the user's OAuth2 credentials to the in-memory cache and the 151 /// Save the user's OAuth2 credentials to the in-memory cache and the
151 /// filesystem. 152 /// filesystem.
152 Future _saveCredentials(SystemCache cache, Credentials credentials) { 153 Future _saveCredentials(SystemCache cache, Credentials credentials) {
153 log.fine('Saving OAuth2 credentials.'); 154 log.fine('Saving OAuth2 credentials.');
154 _credentials = credentials; 155 _credentials = credentials;
155 var path = _credentialsFile(cache); 156 var path = _credentialsFile(cache);
156 return ensureDir(dirname(path)).chain((_) => 157 return ensureDir(dirname(path)).then((_) =>
157 writeTextFile(path, credentials.toJson(), dontLogContents: true)); 158 writeTextFile(path, credentials.toJson(), dontLogContents: true));
158 } 159 }
159 160
160 /// The path to the file in which the user's OAuth2 credentials are stored. 161 /// The path to the file in which the user's OAuth2 credentials are stored.
161 String _credentialsFile(SystemCache cache) => 162 String _credentialsFile(SystemCache cache) =>
162 join(cache.rootDir, 'credentials.json'); 163 join(cache.rootDir, 'credentials.json');
163 164
164 /// Gets the user to authorize pub as a client of pub.dartlang.org via oauth2. 165 /// Gets the user to authorize pub as a client of pub.dartlang.org via oauth2.
165 /// Returns a Future that will complete to a fully-authorized [Client]. 166 /// Returns a Future that will complete to a fully-authorized [Client].
166 Future<Client> _authorize() { 167 Future<Client> _authorize() {
(...skipping 12 matching lines...) Expand all
179 tokenEndpoint, 180 tokenEndpoint,
180 httpClient: curlClient); 181 httpClient: curlClient);
181 182
182 // Spin up a one-shot HTTP server to receive the authorization code from the 183 // Spin up a one-shot HTTP server to receive the authorization code from the
183 // Google OAuth2 server via redirect. This server will close itself as soon as 184 // Google OAuth2 server via redirect. This server will close itself as soon as
184 // the code is received. 185 // the code is received.
185 var completer = new Completer(); 186 var completer = new Completer();
186 var server = new HttpServer(); 187 var server = new HttpServer();
187 server.addRequestHandler((request) => request.path == "/", 188 server.addRequestHandler((request) => request.path == "/",
188 (request, response) { 189 (request, response) {
189 chainToCompleter(new Future.immediate(null).chain((_) { 190 chainToCompleter(new Future.immediate(null).then((_) {
190 log.message('Authorization received, processing...'); 191 log.message('Authorization received, processing...');
191 var queryString = request.queryString; 192 var queryString = request.queryString;
192 if (queryString == null) queryString = ''; 193 if (queryString == null) queryString = '';
193 response.statusCode = 302; 194 response.statusCode = 302;
194 response.headers.set('location', 'http://pub.dartlang.org/authorized'); 195 response.headers.set('location', 'http://pub.dartlang.org/authorized');
195 response.outputStream.close(); 196 response.outputStream.close();
196 return grant.handleAuthorizationResponse(queryToMap(queryString)); 197 return grant.handleAuthorizationResponse(queryToMap(queryString));
197 }).then((client) { 198 }).then((client) {
198 server.close(); 199 server.close();
199 return client; 200 return client;
200 }), completer); 201 }), completer);
201 }); 202 });
202 server.listen('127.0.0.1', 0); 203 server.listen('127.0.0.1', 0);
203 204
204 var authUrl = grant.getAuthorizationUrl( 205 var authUrl = grant.getAuthorizationUrl(
205 new Uri.fromString('http://localhost:${server.port}'), scopes: _scopes); 206 new Uri.fromString('http://localhost:${server.port}'), scopes: _scopes);
206 207
207 log.message( 208 log.message(
208 'Pub needs your authorization to upload packages on your behalf.\n' 209 'Pub needs your authorization to upload packages on your behalf.\n'
209 'In a web browser, go to $authUrl\n' 210 'In a web browser, go to $authUrl\n'
210 'Then click "Allow access".\n\n' 211 'Then click "Allow access".\n\n'
211 'Waiting for your authorization...'); 212 'Waiting for your authorization...');
212 213
213 return completer.future.then((client) { 214 return completer.future.then((client) {
214 log.message('Successfully authorized.\n'); 215 log.message('Successfully authorized.\n');
215 return client; 216 return client;
216 }); 217 });
217 } 218 }
OLDNEW
« no previous file with comments | « utils/pub/log.dart ('k') | utils/pub/validator.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698