Guest User

Untitled

a guest
May 9th, 2020
198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.70 KB | None | 0 0
  1. // TwitPic/OAuth.cs
  2. //
  3. // Code to do OAuth stuff, in support of a cropper plugin that sends
  4. // a screen snap to TwitPic.com.
  5. //
  6. // There's one main class: OAuth.Manager. It handles interaction with the OAuth-
  7. // enabled service, for requesting temporary tokens (aka request tokens), as well
  8. // as access tokens. It also provides a convenient way to construct an oauth
  9. // Authorization header for use in any Http transaction.
  10. //
  11. // The code has been tested with Twitter and TwitPic, from a desktop application.
  12. //
  13. // -------------------------------------------------------
  14. // Dino Chiesa
  15. // Tue, 14 Dec 2010 12:31
  16. //
  17.  
  18.  
  19. namespace OAuth
  20. {
  21. using System;
  22. using System.Linq;
  23. using System.Collections.Generic;
  24. using System.Security.Cryptography;
  25.  
  26. //using CropperPlugins.Utils;
  27.  
  28. /// <summary>
  29. /// A class to manage OAuth interactions. This works with
  30. /// Twitter, not sure about other OAuth-enabled services.
  31. /// </summary>
  32. /// <remarks>
  33. /// <para>
  34. /// This class holds the relevant oauth parameters, and exposes
  35. /// methods that do things, based on those params.
  36. /// </para>
  37. /// <para>
  38. /// See http://dev.twitpic.com/docs/2/upload/ for an example of the
  39. /// oauth parameters. The params include token, consumer_key,
  40. /// timestamp, version, and so on. In the actual HTTP message, they
  41. /// all include the oauth_ prefix, so .. oauth_token,
  42. /// oauth_timestamp, and so on. You set these via a string indexer.
  43. /// If the instance of the class is called oauth, then to set
  44. /// the oauth_token parameter, you use oath["token"] in C#.
  45. /// </para>
  46. /// <para>
  47. /// This class automatically sets many of the required oauth parameters;
  48. /// this includes the timestamp, nonce, callback, and version parameters.
  49. /// (The callback param is initialized to 'oob'). You can reset any of
  50. /// these parameters as you see fit. In many cases you won't have to.
  51. /// </para>
  52. /// <para>
  53. /// The public methods on the class include:
  54. /// AcquireRequestToken, AcquireAccessToken,
  55. /// GenerateCredsHeader, and GenerateAuthorizationHeader. The
  56. /// first two are used only on the first run of an applicaiton,
  57. /// or after a user has explicitly de-authorized an application
  58. /// for use with OAuth. Normally, the GenerateXxxHeader methods
  59. /// can be used repeatedly, when sending HTTP messages that
  60. /// require an OAuth Authorization header.
  61. /// </para>
  62. /// <para>
  63. /// The AcquireRequestToken and AcquireAccessToken methods
  64. /// actually send out HTTP messages.
  65. /// </para>
  66. /// <para>
  67. /// The GenerateXxxxHeaders are used when constructing and
  68. /// sending your own HTTP messages.
  69. /// </para>
  70. /// </remarks>
  71. public class Manager
  72. {
  73. /// <summary>
  74. /// The default public constructor.
  75. /// </summary>
  76. /// <remarks>
  77. /// <para>
  78. /// Initializes various fields to default values.
  79. /// </para>
  80. /// </remarks>
  81. public Manager()
  82. {
  83. _random = new Random();
  84. _params = new Dictionary<String,String>();
  85. _params["callback"] = "oob"; // presume "desktop" consumer
  86. _params["consumer_key"] = "";
  87. _params["consumer_secret"] = "";
  88. _params["timestamp"] = GenerateTimeStamp();
  89. _params["nonce"] = GenerateNonce();
  90. _params["signature_method"] = "HMAC-SHA1";
  91. _params["signature"] = "";
  92. _params["token"] = "";
  93. _params["token_secret"] = "";
  94. _params["version"] = "1.0";
  95. }
  96.  
  97. /// <summary>
  98. /// The constructor to use when using OAuth when you already
  99. /// have an OAuth access token.
  100. /// </summary>
  101. /// <remarks>
  102. /// <para>
  103. /// The parameters for this constructor all have the
  104. /// meaning you would expect. The token and tokenSecret
  105. /// are set in oauth_token, and oauth_token_secret.
  106. /// These are *Access* tokens, obtained after a call
  107. /// to AcquireAccessToken. The application can store
  108. /// those tokens and re-use them on successive runs.
  109. /// For twitter at least, the access tokens never expire.
  110. /// </para>
  111. /// </remarks>
  112. public Manager(string consumerKey,
  113. string consumerSecret,
  114. string token,
  115. string tokenSecret) : this()
  116.  
  117. {
  118. _params["consumer_key"] = consumerKey;
  119. _params["consumer_secret"] = consumerSecret;
  120. _params["token"] = token;
  121. _params["token_secret"] = tokenSecret;
  122. }
  123.  
  124. /// <summary>
  125. /// string indexer to get or set oauth parameter values.
  126. /// </summary>
  127. /// <remarks>
  128. /// <para>
  129. /// Use the parameter name *without* the oauth_ prefix.
  130. /// If you want to set the value for the oauth_token parameter
  131. /// field in an HTTP message, then use oauth["token"].
  132. /// </para>
  133. /// <para>
  134. /// The set of oauth param names known by this indexer includes:
  135. /// callback, consumer_key, consumer_secret, timestamp, nonce,
  136. /// signature_method, signature, token, token_secret, and version.
  137. /// </para>
  138. /// <para>
  139. /// If you try setting a parameter with a name that is not known,
  140. /// the setter will throw. You cannot add new oauth parameters
  141. /// using the setter on this indexer.
  142. /// </para>
  143. /// </remarks>
  144. public string this[string ix]
  145. {
  146. get
  147. {
  148. if (_params.ContainsKey(ix))
  149. return _params[ix];
  150. throw new ArgumentException(ix);
  151. }
  152. set
  153. {
  154. if (!_params.ContainsKey(ix))
  155. throw new ArgumentException(ix);
  156. _params[ix] = value;
  157. }
  158. }
  159.  
  160.  
  161. /// <summary>
  162. /// Generate the timestamp for the signature.
  163. /// </summary>
  164. /// <returns>The timestamp, in string form.</returns>
  165. private string GenerateTimeStamp()
  166. {
  167. TimeSpan ts = DateTime.UtcNow - _epoch;
  168. return Convert.ToInt64(ts.TotalSeconds).ToString();
  169. }
  170.  
  171. /// <summary>
  172. /// Renews the nonce and timestamp on the oauth parameters.
  173. /// </summary>
  174. /// <remarks>
  175. /// <para>
  176. /// Each new request should get a new, current timestamp, and a
  177. /// nonce. This helper method does both of those things. This gets
  178. /// called before generating an authorization header, as for example
  179. /// when the user of this class calls <see cref='AcquireRequestToken'>.
  180. /// </para>
  181. /// </remarks>
  182. private void NewRequest()
  183. {
  184. _params["nonce"] = GenerateNonce();
  185. _params["timestamp"] = GenerateTimeStamp();
  186. }
  187.  
  188. /// <summary>
  189. /// Generate an oauth nonce.
  190. /// </summary>
  191. /// <remarks>
  192. /// <para>
  193. /// According to RFC 5849, A nonce is a random string,
  194. /// uniquely generated by the client to allow the server to
  195. /// verify that a request has never been made before and
  196. /// helps prevent replay attacks when requests are made over
  197. /// a non-secure channel. The nonce value MUST be unique
  198. /// across all requests with the same timestamp, client
  199. /// credentials, and token combinations.
  200. /// </para>
  201. /// <para>
  202. /// One way to implement the nonce is just to use a
  203. /// monotonically-increasing integer value. It starts at zero and
  204. /// increases by 1 for each new request or signature generated.
  205. /// Keep in mind the nonce needs to be unique only for a given
  206. /// timestamp! So if your app makes less than one request per
  207. /// second, then using a static nonce of "0" will work.
  208. /// </para>
  209. /// <para>
  210. /// Most oauth nonce generation routines are waaaaay over-engineered,
  211. /// and this one is no exception.
  212. /// </para>
  213. /// </remarks>
  214. /// <returns>the nonce</returns>
  215. private string GenerateNonce()
  216. {
  217. var sb = new System.Text.StringBuilder();
  218. for (int i=0; i < 8; i++)
  219. {
  220. int g = _random.Next(3);
  221. switch(g)
  222. {
  223. case 0:
  224. // lowercase alpha
  225. sb.Append( (char)(_random.Next(26)+97), 1);
  226. break;
  227. default:
  228. // numeric digits
  229. sb.Append( (char)(_random.Next(10)+48), 1);
  230. break;
  231. }
  232. }
  233. return sb.ToString();
  234. }
  235.  
  236.  
  237. /// <summary>
  238. /// Internal function to extract from a URL all query string
  239. /// parameters that are not related to oauth - in other words all
  240. /// parameters not begining with "oauth_".
  241. /// </summary>
  242. ///
  243. /// <remarks>
  244. /// <para>
  245. /// For example, given a url like http://foo?a=7&guff, the
  246. /// returned value will be a Dictionary of string-to-string
  247. /// relations. There will be 2 entries in the Dictionary: "a"=>7,
  248. /// and "guff"=>"".
  249. /// </para>
  250. /// </remarks>
  251. ///
  252. /// <param name="queryString">The query string part of the Url</param>
  253. ///
  254. /// <returns>A Dictionary containing the set of
  255. /// parameter names and associated values</returns>
  256. private Dictionary<String,String> ExtractQueryParameters(string queryString)
  257. {
  258. if (queryString.StartsWith("?"))
  259. queryString = queryString.Remove(0, 1);
  260.  
  261. var result = new Dictionary<String,String>();
  262.  
  263. if (string.IsNullOrEmpty(queryString))
  264. return result;
  265.  
  266. foreach (string s in queryString.Split('&'))
  267. {
  268. if (!string.IsNullOrEmpty(s) && !s.StartsWith("oauth_"))
  269. {
  270. if (s.IndexOf('=') > -1)
  271. {
  272. string[] temp = s.Split('=');
  273. result.Add(temp[0], temp[1]);
  274. }
  275. else
  276. result.Add(s, string.Empty);
  277. }
  278. }
  279.  
  280. return result;
  281. }
  282.  
  283.  
  284.  
  285. /// <summary>
  286. /// This is an oauth-compliant Url Encoder. The default .NET
  287. /// encoder outputs the percent encoding in lower case. While this
  288. /// is not a problem with the percent encoding defined in RFC 3986,
  289. /// OAuth (RFC 5849) requires that the characters be upper case
  290. /// throughout OAuth.
  291. /// </summary>
  292. ///
  293. /// <param name="value">The value to encode</param>
  294. ///
  295. /// <returns>the Url-encoded version of that string</returns>
  296. public static string UrlEncode(string value)
  297. {
  298. var result = new System.Text.StringBuilder();
  299. foreach (char symbol in value)
  300. {
  301. if (unreservedChars.IndexOf(symbol) != -1)
  302. result.Append(symbol);
  303. else
  304. result.Append('%' + String.Format("{0:X2}", (int)symbol));
  305. }
  306. return result.ToString();
  307. }
  308. private static string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
  309.  
  310.  
  311. /// <summary>
  312. /// Formats the list of request parameters into string a according
  313. /// to the requirements of oauth. The resulting string could be used
  314. /// in the Authorization header of the request.
  315. /// </summary>
  316. ///
  317. /// <remarks>
  318. /// <para>
  319. /// See http://dev.twitter.com/pages/auth#intro for some
  320. /// background. The output of this is not suitable for signing.
  321. /// </para>
  322. /// <para>
  323. /// There are 2 formats for specifying the list of oauth
  324. /// parameters in the oauth spec: one suitable for signing, and
  325. /// the other suitable for use within Authorization HTTP Headers.
  326. /// This method emits a string suitable for the latter.
  327. /// </para>
  328. /// </remarks>
  329. ///
  330. /// <param name="parameters">The Dictionary of
  331. /// parameters. It need not be sorted.</param>
  332. ///
  333. /// <returns>a string representing the parameters</returns>
  334. private static string EncodeRequestParameters(ICollection<KeyValuePair<String,String>> p)
  335. {
  336. var sb = new System.Text.StringBuilder();
  337. foreach (KeyValuePair<String,String> item in p.OrderBy(x => x.Key))
  338. {
  339. if (!String.IsNullOrEmpty(item.Value) &&
  340. !item.Key.EndsWith("secret"))
  341. sb.AppendFormat("oauth_{0}=\"{1}\", ",
  342. item.Key,
  343. UrlEncode(item.Value));
  344. }
  345.  
  346. return sb.ToString().TrimEnd(' ').TrimEnd(',');
  347. }
  348.  
  349.  
  350.  
  351. /// <summary>
  352. /// Acquire a request token, from the given URI, using the given
  353. /// HTTP method.
  354. /// </summary>
  355. ///
  356. /// <remarks>
  357. /// <para>
  358. /// To use this method, first instantiate a new Oauth.Manager object,
  359. /// then set the callback param (oauth["callback"]='oob'). After the
  360. /// call returns, you should direct the user to open a browser window
  361. /// to the authorization page for the OAuth-enabled service. Or,
  362. /// you can automatically open that page yourself. Do this with
  363. /// System.Diagnostics.Process.Start(), passing the URL of the page.
  364. /// There should be one query param: oauth_token with the value
  365. /// obtained from oauth["token"].
  366. /// </para>
  367. /// <para>
  368. /// According to the OAuth spec, you need to do this only ONCE per
  369. /// application. In other words, the first time the application
  370. /// is run. The normal oauth workflow is: (1) get a request token,
  371. /// (2) use that to acquire an access token (which requires explicit
  372. /// user approval), then (3) using that access token, invoke
  373. /// protected services. The first two steps need to be done only
  374. /// once per application.
  375. /// </para>
  376. /// <para>
  377. /// For Twitter, at least, you can cache the access tokens
  378. /// indefinitely; Twitter says they never expire. However, other
  379. /// oauth services may not do the same. Also: the user may at any
  380. /// time revoke his authorization for your app, in which case you
  381. /// need to perform the first 2 steps again.
  382. /// </para>
  383. /// </remarks>
  384. ///
  385. /// <seealso cref='AcquireAccessToken'>
  386. ///
  387. /// </example>
  388. /// <returns>
  389. /// a response object that contains the entire text of the response,
  390. /// as well as extracted parameters. This method presumes the
  391. /// response is query-param encoded. In other words,
  392. /// poauth_token=foo&something_else=bar.
  393. /// </returns>
  394. public OAuthResponse AcquireRequestToken(string uri, string method)
  395. {
  396. NewRequest();
  397. var authzHeader = GetAuthorizationHeader(uri, method);
  398.  
  399. // prepare the token request
  400. var request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri);
  401. request.Headers.Add("Authorization", authzHeader);
  402. request.Method = method;
  403.  
  404. using (var response = (System.Net.HttpWebResponse)request.GetResponse())
  405. {
  406. using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
  407. {
  408. var r = new OAuthResponse(reader.ReadToEnd());
  409. this["token"] = r["oauth_token"];
  410.  
  411. // Sometimes the request_token URL gives us an access token,
  412. // with no user interaction required. Eg, when prior approval
  413. // has already been granted.
  414. try
  415. {
  416. if (r["oauth_token_secret"] != null)
  417. this["token_secret"] = r["oauth_token_secret"];
  418. }
  419. catch { }
  420. return r;
  421. }
  422. }
  423. }
  424.  
  425.  
  426. /// <summary>
  427. /// Acquire an access token, from the given URI, using the given
  428. /// HTTP method.
  429. /// </summary>
  430. ///
  431. /// <remarks>
  432. /// <para>
  433. /// To use this method, you must first set the oauth_token to the value
  434. /// of the request token. Eg, oauth["token"] = "whatever".
  435. /// </para>
  436. /// <para>
  437. /// According to the OAuth spec, you need to do this only ONCE per
  438. /// application. In other words, the first time the application
  439. /// is run. The normal oauth workflow is: (1) get a request token,
  440. /// (2) use that to acquire an access token (which requires explicit
  441. /// user approval), then (3) using that access token, invoke
  442. /// protected services. The first two steps need to be done only
  443. /// once per application.
  444. /// </para>
  445. /// <para>
  446. /// For Twitter, at least, you can cache the access tokens
  447. /// indefinitely; Twitter says they never expire. However, other
  448. /// oauth services may not do the same. Also: the user may at any
  449. /// time revoke his authorization for your app, in which case you
  450. /// need to perform the first 2 steps again.
  451. /// </para>
  452. /// </remarks>
  453. ///
  454. /// <seealso cref='AcquireRequestToken'>
  455. ///
  456. /// </example>
  457. /// <returns>
  458. /// a response object that contains the entire text of the response,
  459. /// as well as extracted parameters. This method presumes the
  460. /// response is query-param encoded. In other words,
  461. /// poauth_token=foo&something_else=bar.
  462. /// </returns>
  463. public OAuthResponse AcquireAccessToken(string uri, string method, string pin)
  464. {
  465. NewRequest();
  466. _params["verifier"] = pin;
  467.  
  468. var authzHeader = GetAuthorizationHeader(uri, method);
  469.  
  470. // prepare the token request
  471. var request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri);
  472. request.Headers.Add("Authorization", authzHeader);
  473. request.Method = method;
  474.  
  475. using (var response = (System.Net.HttpWebResponse)request.GetResponse())
  476. {
  477. using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
  478. {
  479. var r = new OAuthResponse(reader.ReadToEnd());
  480. this["token"] = r["oauth_token"];
  481. this["token_secret"] = r["oauth_token_secret"];
  482. return r;
  483. }
  484. }
  485. }
  486.  
  487.  
  488. /// <summary>
  489. /// Generate a string to be used in an Authorization header in
  490. /// an HTTP request.
  491. /// </summary>
  492. /// <remarks>
  493. /// <para>
  494. /// This method assembles the available oauth_ parameters that
  495. /// have been set in the Dictionary in this instance, produces
  496. /// the signature base (As described by the OAuth spec, RFC 5849),
  497. /// signs it, then re-formats the oauth_ parameters into the
  498. /// appropriate form, including the oauth_signature value, and
  499. /// returns the result.
  500. /// </para>
  501. /// <para>
  502. /// If you pass in a non-null, non-empty realm, this method will
  503. /// include the realm='foo' clause in the Authorization header.
  504. /// </para>
  505. /// </remarks>
  506. ///
  507. /// <seealso cref='GenerateAuthzHeader'>
  508. public string GenerateCredsHeader(string uri, string method, string realm)
  509. {
  510. NewRequest();
  511. var authzHeader = GetAuthorizationHeader(uri, method, realm);
  512. return authzHeader;
  513. }
  514.  
  515.  
  516. /// <summary>
  517. /// Generate a string to be used in an Authorization header in
  518. /// an HTTP request.
  519. /// </summary>
  520. /// <remarks>
  521. /// <para>
  522. /// This method assembles the available oauth_ parameters that
  523. /// have been set in the Dictionary in this instance, produces
  524. /// the signature base (As described by the OAuth spec, RFC 5849),
  525. /// signs it, then re-formats the oauth_ parameters into the
  526. /// appropriate form, including the oauth_signature value, and
  527. /// returns the result.
  528. /// </para>
  529. /// </remarks>
  530. ///
  531. /// <seealso cref='GenerateAuthzHeader'>
  532. public string GenerateAuthzHeader(string uri, string method)
  533. {
  534. NewRequest();
  535. var authzHeader = GetAuthorizationHeader(uri, method, null);
  536. return authzHeader;
  537. }
  538.  
  539. private string GetAuthorizationHeader(string uri, string method)
  540. {
  541. return GetAuthorizationHeader(uri, method, null);
  542. }
  543.  
  544. private string GetAuthorizationHeader(string uri, string method, string realm)
  545. {
  546. if (string.IsNullOrEmpty(this._params["consumer_key"]))
  547. throw new ArgumentNullException("consumer_key");
  548.  
  549. if (string.IsNullOrEmpty(this._params["signature_method"]))
  550. throw new ArgumentNullException("signature_method");
  551.  
  552. Sign(uri, method);
  553.  
  554. var erp = EncodeRequestParameters(this._params);
  555. //Tracing.Trace("erp = {0}", erp);
  556. return (String.IsNullOrEmpty(realm))
  557. ? "OAuth " + erp
  558. : String.Format("OAuth realm=\"{0}\", ", realm) + erp;
  559. }
  560.  
  561.  
  562. private void Sign(string uri, string method)
  563. {
  564. var signatureBase = GetSignatureBase(uri, method);
  565. var hash = GetHash();
  566.  
  567. byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(signatureBase);
  568. byte[] hashBytes = hash.ComputeHash(dataBuffer);
  569.  
  570. this["signature"] = Convert.ToBase64String(hashBytes);
  571. }
  572.  
  573. /// <summary>
  574. /// Formats the list of request parameters into "signature base" string as
  575. /// defined by RFC 5849. This will then be MAC'd with a suitable hash.
  576. /// </summary>
  577. private string GetSignatureBase(string url, string method)
  578. {
  579. // normalize the URI
  580. var uri = new Uri(url);
  581. var normUrl = string.Format("{0}://{1}", uri.Scheme, uri.Host);
  582. if (!((uri.Scheme == "http" && uri.Port == 80) ||
  583. (uri.Scheme == "https" && uri.Port == 443)))
  584. normUrl += ":" + uri.Port;
  585.  
  586. normUrl += uri.AbsolutePath;
  587.  
  588. // the sigbase starts with the method and the encoded URI
  589. var sb = new System.Text.StringBuilder();
  590. sb.Append(method)
  591. .Append('&')
  592. .Append(UrlEncode(normUrl))
  593. .Append('&');
  594.  
  595. // the parameters follow - all oauth params plus any params on
  596. // the uri
  597. // each uri may have a distinct set of query params
  598. var p = ExtractQueryParameters(uri.Query);
  599. // add all non-empty params to the "current" params
  600. foreach (var p1 in this._params)
  601. {
  602. // Exclude all oauth params that are secret or
  603. // signatures; any secrets should be kept to ourselves,
  604. // and any existing signature will be invalid.
  605. if (!String.IsNullOrEmpty(this._params[p1.Key]) &&
  606. !p1.Key.EndsWith("_secret") &&
  607. !p1.Key.EndsWith("signature"))
  608. p.Add("oauth_" + p1.Key, p1.Value);
  609. }
  610.  
  611. // concat+format all those params
  612. var sb1 = new System.Text.StringBuilder();
  613. foreach (KeyValuePair<String,String> item in p.OrderBy(x => x.Key))
  614. {
  615. // even "empty" params need to be encoded this way.
  616. sb1.AppendFormat("{0}={1}&", item.Key, item.Value);
  617. }
  618.  
  619. // append the UrlEncoded version of that string to the sigbase
  620. sb.Append(UrlEncode(sb1.ToString().TrimEnd('&')));
  621. var result = sb.ToString();
  622. //Tracing.Trace("Sigbase: '{0}'", result);
  623. return result;
  624. }
  625.  
  626.  
  627.  
  628. private HashAlgorithm GetHash()
  629. {
  630. if (this["signature_method"] != "HMAC-SHA1")
  631. throw new NotImplementedException();
  632.  
  633. string keystring = string.Format("{0}&{1}",
  634. UrlEncode(this["consumer_secret"]),
  635. UrlEncode(this["token_secret"]));
  636. //Tracing.Trace("keystring: '{0}'", keystring);
  637. var hmacsha1 = new HMACSHA1
  638. {
  639. Key = System.Text.Encoding.ASCII.GetBytes(keystring)
  640. };
  641. return hmacsha1;
  642. }
  643.  
  644. #if BROKEN
  645. /// <summary>
  646. /// Return the oauth string that can be used in an Authorization
  647. /// header. All the oauth terms appear in the string, in alphabetical
  648. /// order.
  649. /// </summary>
  650. public string GetOAuthHeader()
  651. {
  652. return EncodeRequestParameters(this._params);
  653. }
  654. #endif
  655. private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
  656. private Dictionary<String,String> _params;
  657. private Random _random;
  658. }
  659.  
  660.  
  661. /// <summary>
  662. /// A class to hold an OAuth response MessageBox.
  663. /// </summary>
  664. public class OAuthResponse
  665. {
  666. /// <summary>
  667. /// All of the text in the response. This is useful if the app wants
  668. /// to do its own parsing.
  669. /// </summary>
  670. public string AllText { get;set; }
  671. private Dictionary<String,String> _params;
  672.  
  673. /// <summary>
  674. /// a Dictionary of response parameters.
  675. /// </summary>
  676. public string this[string ix]
  677. {
  678. get
  679. {
  680. return _params[ix];
  681. }
  682. }
  683.  
  684.  
  685. public OAuthResponse(string alltext)
  686. {
  687. AllText = alltext;
  688. _params = new Dictionary<String,String>();
  689. var kvpairs = alltext.Split('&');
  690. foreach (var pair in kvpairs)
  691. {
  692. var kv = pair.Split('=');
  693. _params.Add(kv[0],kv[1]);
  694. }
  695. // expected keys:
  696. // oauth_token, oauth_token_secret, user_id, screen_name, etc
  697. }
  698. }
  699. }
Add Comment
Please, Sign In to add comment