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.utils; | 5 library oauth2.utils; |
6 | 6 |
| 7 import 'dart:convert'; |
| 8 |
| 9 import 'package:crypto/crypto.dart'; |
| 10 |
7 /// Adds additional query parameters to [url], overwriting the original | 11 /// Adds additional query parameters to [url], overwriting the original |
8 /// parameters if a name conflict occurs. | 12 /// parameters if a name conflict occurs. |
9 Uri addQueryParameters(Uri url, Map<String, String> parameters) => url.replace( | 13 Uri addQueryParameters(Uri url, Map<String, String> parameters) => url.replace( |
10 queryParameters: new Map.from(url.queryParameters)..addAll(parameters)); | 14 queryParameters: new Map.from(url.queryParameters)..addAll(parameters)); |
11 | 15 |
12 /// Like [String.split], but only splits on the first occurrence of the pattern. | 16 String basicAuthHeader(String identifier, String secret) { |
13 /// | 17 var userPass = Uri.encodeFull(identifier) + ":" + Uri.encodeFull(secret); |
14 /// This will always return a list of two elements or fewer. | 18 return "Basic " + CryptoUtils.bytesToBase64(ASCII.encode(userPass)); |
15 List<String> split1(String toSplit, String pattern) { | |
16 if (toSplit.isEmpty) return []; | |
17 | |
18 var index = toSplit.indexOf(pattern); | |
19 if (index == -1) return [toSplit]; | |
20 return [toSplit.substring(0, index), | |
21 toSplit.substring(index + pattern.length)]; | |
22 } | 19 } |
23 | |
24 /// A WWW-Authenticate header value, parsed as per [RFC 2617][]. | |
25 /// | |
26 /// [RFC 2617]: http://tools.ietf.org/html/rfc2617 | |
27 class AuthenticateHeader { | |
28 final String scheme; | |
29 final Map<String, String> parameters; | |
30 | |
31 AuthenticateHeader(this.scheme, this.parameters); | |
32 | |
33 /// Parses a header string. Throws a [FormatException] if the header is | |
34 /// invalid. | |
35 factory AuthenticateHeader.parse(String header) { | |
36 var split = split1(header, ' '); | |
37 if (split.length == 0) { | |
38 throw new FormatException('Invalid WWW-Authenticate header: "$header"'); | |
39 } else if (split.length == 1 || split[1].trim().isEmpty) { | |
40 return new AuthenticateHeader(split[0].toLowerCase(), {}); | |
41 } | |
42 var scheme = split[0].toLowerCase(); | |
43 var paramString = split[1]; | |
44 | |
45 // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html. | |
46 var tokenChar = r'[^\0-\x1F()<>@,;:\\"/\[\]?={} \t\x7F]'; | |
47 var quotedStringChar = r'(?:[^\0-\x1F\x7F"]|\\.)'; | |
48 var regexp = new RegExp('^ *($tokenChar+)="($quotedStringChar*)" *(, *)?'); | |
49 | |
50 var parameters = {}; | |
51 var match; | |
52 do { | |
53 match = regexp.firstMatch(paramString); | |
54 if (match == null) { | |
55 throw new FormatException('Invalid WWW-Authenticate header: "$header"'); | |
56 } | |
57 | |
58 paramString = paramString.substring(match.end); | |
59 parameters[match.group(1).toLowerCase()] = match.group(2); | |
60 } while (match.group(3) != null); | |
61 | |
62 if (!paramString.trim().isEmpty) { | |
63 throw new FormatException('Invalid WWW-Authenticate header: "$header"'); | |
64 } | |
65 | |
66 return new AuthenticateHeader(scheme, parameters); | |
67 } | |
68 } | |
OLD | NEW |