public async Task <Credentials> Authenticate(string code, CancellationToken cancel, IProgress <ProgressChangedEventArgs> progress = null) { var fields = new Dictionary <string, string>(); fields["grant_type"] = "authorization_code"; fields["code"] = code; fields["redirect_uri"] = "flashcards://complete-oauth"; var basicAuth = new KeyValuePair <string, string>(clientID, secretKey); var json = await Fetch(new Uri("/oauth/token", UriKind.Relative), RequestType.Post, false, cancel, progress, fields, basicAuth); var dict = JsonDictionary.FromValue(json); var ctx = new JsonContext(); // TODO Should probably check token_type and scope properties to check we have the right type of token! return(new Credentials( ctx.FromJson <string>(dict["user_id"]), DateTime.UtcNow.AddSeconds(ctx.FromJson <double>(dict["expires_in"])), ctx.FromJson <string>(dict["access_token"]))); }
/// <summary> /// Takes an OAuth code and turns it into an API token. /// </summary> /// <param name="code">A code returned from the OAuth page (https://quizlet.com/authorize/)</param> /// <param name="success">A delegate to be called when the authentication succeeds.</param> /// <param name="failure">What to do when the authentication fails.</param> /// <param name="token">A CancellationToken, which is currently useless.</param> public void Authenticate(string code, Action success, Action <Exception> failure, CancellationToken token) { var fields = "grant_type=authorization_code&code=" + code + "&redirect_uri=https://q.asztal.net/"; var req = new HttpsRequest("POST", "/oauth/token"); req.BasicAuthorization(ClientID, SecretKey); req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; req.PostData = Encoding.UTF8.GetBytes(fields); FetchJSON(req, json => { try { if (json is JsonDictionary) { var ctx = new JsonContext(); var accessToken = ctx.FromJson <string>((json as JsonDictionary).Items["access_token"]); var userName = ctx.FromJson <string>((json as JsonDictionary).Items["user_id"]); var tokenExpiry = DateTime.Now.AddSeconds(ctx.FromJson <double>((json as JsonDictionary).Items["expires_in"])); Credentials = new Credentials(accessToken, userName, tokenExpiry); success(); } else { failure(new FormatException("Quizlet server returned an invalid response.")); } } catch (KeyNotFoundException) { failure(new FormatException("Quizlet server returned an invalid response.")); } catch (JsonConvertException) { failure(new FormatException("Quizlet server returned an invalid response.")); } }, failure, token); }
public void CreateSet(SetInfo si, string password, IEnumerable <long> groupIDs, Action <long, Uri> completion, Action <Exception> errorHandler, CancellationToken token) { var req = new HttpsRequest("POST", "/2.0/sets"); var postData = new MemoryStream(); using (var writer = new StreamWriter(postData)) WriteSetInfo(si, writer, password, si.Visibility, si.Editable, groupIDs); req.ContentType = "application/x-www-form-urlencoded"; req.PostData = postData.ToArray(); AuthorizeRequest(req, true); FetchJSON( req, json => { try { if (!(json is JsonDictionary)) { throw new JsonConvertException("Expected a JSON dictionary"); } var ctx = new JsonContext(); var dict = (json as JsonDictionary).Items; var uri = new Uri(ctx.FromJson <string>(dict["url"])); var id = ctx.FromJson <long>(dict["set_id"]); completion(id, uri); } catch (JsonConvertException err) { errorHandler(err); } catch (KeyNotFoundException err) { errorHandler(new QuizletException("Invalid response from server", err)); } }, errorHandler, token); }
/// <summary> /// Takes an OAuth code and turns it into an API token. /// </summary> /// <param name="code">A code returned from the OAuth page (https://quizlet.com/authorize/)</param> /// <param name="success">A delegate to be called when the authentication succeeds.</param> /// <param name="failure">What to do when the authentication fails.</param> /// <param name="token">A CancellationToken, which is currently useless.</param> public void Authenticate(string code, Action success, Action<Exception> failure, CancellationToken token) { var fields = "grant_type=authorization_code&code=" + code + "&redirect_uri=https://q.asztal.net/"; var req = new HttpsRequest("POST", "/oauth/token"); req.BasicAuthorization(ClientID, SecretKey); req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; req.PostData = Encoding.UTF8.GetBytes(fields); FetchJSON(req, json => { try { if (json is JsonDictionary) { var ctx = new JsonContext(); var accessToken = ctx.FromJson<string>((json as JsonDictionary).Items["access_token"]); var userName = ctx.FromJson<string>((json as JsonDictionary).Items["user_id"]); var tokenExpiry = DateTime.Now.AddSeconds(ctx.FromJson<double>((json as JsonDictionary).Items["expires_in"])); Credentials = new Credentials(accessToken, userName, tokenExpiry); success(); } else { failure(new FormatException("Quizlet server returned an invalid response.")); } } catch (KeyNotFoundException) { failure(new FormatException("Quizlet server returned an invalid response.")); } catch (JsonConvertException) { failure(new FormatException("Quizlet server returned an invalid response.")); } }, failure, token); }
public void CreateSet(SetInfo si, string password, IEnumerable<long> groupIDs, Action<long, Uri> completion, Action<Exception> errorHandler, CancellationToken token) { var req = new HttpsRequest("POST", "/2.0/sets"); var postData = new MemoryStream(); using (var writer = new StreamWriter(postData)) WriteSetInfo(si, writer, password, si.Visibility, si.Editable, groupIDs); req.ContentType = "application/x-www-form-urlencoded"; req.PostData = postData.ToArray(); AuthorizeRequest(req, true); FetchJSON( req, json => { try { if (!(json is JsonDictionary)) throw new JsonConvertException("Expected a JSON dictionary"); var ctx = new JsonContext(); var dict = (json as JsonDictionary).Items; var uri = new Uri(ctx.FromJson<string>(dict["url"])); var id = ctx.FromJson<long>(dict["set_id"]); completion(id, uri); } catch (JsonConvertException err) { errorHandler(err); } catch (KeyNotFoundException err) { errorHandler(new QuizletException("Invalid response from server", err)); } }, errorHandler, token); }
protected async Task<JsonValue> Fetch( Uri endPoint, RequestType requestType, bool needsToken, CancellationToken cancel, IProgress<ProgressChangedEventArgs> progress = null, IDictionary<string, string> postData = null, KeyValuePair<string,string>? overrideAuth = null) { if (endPoint == null) throw new ArgumentNullException("endPoint"); var wc = new WebClient(); if (needsToken && !Credentials.HasValue) throw new InvalidOperationException("Cannot access this part of the Quizlet service without logging in."); wc.Headers["User-Agent"] = "FlashcardsWP8/0.1 (" + Environment.OSVersion + "; .NET " + Environment.Version + ")"; // Overriding is used for basic authentication for OAuth process. bool useClientID = false; if (overrideAuth != null) wc.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(overrideAuth.Value.Key + ":" + overrideAuth.Value.Value)); else if (Credentials != null) wc.Headers["Authorization"] = "Bearer " + Credentials.Value.ApiToken; else useClientID = true; try { string result; if (requestType == RequestType.Get) { var uri = new Uri(ServiceUri, endPoint); uri = new Uri(uri + (uri.Query == "" ? "?" : "&") + "client_id=" + clientID); result = await wc.DownloadStringAsTask(uri, cancel, progress); } else { var sb = new StringBuilder(); wc.Headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"; wc.Encoding = Encoding.UTF8; if (postData != null) { if (useClientID) postData["client_id"] = clientID; foreach (var kvp in postData) { if (sb.Length > 0) sb.Append('&'); sb.Append(kvp.Key).Append('=').Append(Uri.EscapeDataString(kvp.Value)); } } result = await wc.UploadStringAsTask(new Uri(ServiceUri, endPoint), requestType.ToString().ToUpperInvariant(), sb.ToString(), cancel, progress); } JsonValue json = null; // In case of HTTP status 204 (no content). This is produced, for example, as the result of // a DELETE call to an endpoint. if (!string.IsNullOrWhiteSpace(result)) json = JsonValue.Parse(new StringReader(result)); return json; } catch (WebException e) { // The Quizlet API returns a JSON document explaining the error if there is one, // so try to use that if possible. try { if (e.Response != null) { var response = (e.Response as HttpWebResponse).GetResponseStream(); using (var reader = new StreamReader(response)) { var dict = JsonDictionary.FromValue(JsonValue.Parse(reader)); var ctx = new JsonContext(); var errorCode = ctx.FromJson<string>(dict["error"]); var errorText = ctx.FromJson<string>(dict["error_description"]); if (errorCode != null && errorText != null) { switch (errorCode) { case "invalid_access": throw new AccessDeniedException(errorText); case "item_not_found": throw new ItemNotFoundException(errorText); case "item_deleted": throw new ItemDeletedException(errorText); default: throw new QuizletException(errorText); } } } } throw new QuizletException(string.Format("Unable to contact the Quizlet server ({0}).", e.Message), e); } catch (FormatException) { // Not JSON or invalid - just wrap the original exception throw new QuizletException(e.Message, e); } catch (KeyNotFoundException) { throw new QuizletException(e.Message, e); } } }
public async Task<Credentials> Authenticate(string code, CancellationToken cancel, IProgress<ProgressChangedEventArgs> progress = null) { var fields = new Dictionary<string, string>(); fields["grant_type"] = "authorization_code"; fields["code"] = code; fields["redirect_uri"] = "flashcards://complete-oauth"; var basicAuth = new KeyValuePair<string, string>(clientID, secretKey); var json = await Fetch(new Uri("/oauth/token", UriKind.Relative), RequestType.Post, false, cancel, progress, fields, basicAuth); var dict = JsonDictionary.FromValue(json); var ctx = new JsonContext(); // TODO Should probably check token_type and scope properties to check we have the right type of token! return new Credentials( ctx.FromJson<string>(dict["user_id"]), DateTime.UtcNow.AddSeconds(ctx.FromJson<double>(dict["expires_in"])), ctx.FromJson<string>(dict["access_token"])); }
protected async Task <JsonValue> Fetch( Uri endPoint, RequestType requestType, bool needsToken, CancellationToken cancel, IProgress <ProgressChangedEventArgs> progress = null, IDictionary <string, string> postData = null, KeyValuePair <string, string>?overrideAuth = null) { if (endPoint == null) { throw new ArgumentNullException("endPoint"); } var wc = new WebClient(); if (needsToken && !Credentials.HasValue) { throw new InvalidOperationException("Cannot access this part of the Quizlet service without logging in."); } wc.Headers["User-Agent"] = "FlashcardsWP8/0.1 (" + Environment.OSVersion + "; .NET " + Environment.Version + ")"; // Overriding is used for basic authentication for OAuth process. bool useClientID = false; if (overrideAuth != null) { wc.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(overrideAuth.Value.Key + ":" + overrideAuth.Value.Value)); } else if (Credentials != null) { wc.Headers["Authorization"] = "Bearer " + Credentials.Value.ApiToken; } else { useClientID = true; } try { string result; if (requestType == RequestType.Get) { var uri = new Uri(ServiceUri, endPoint); uri = new Uri(uri + (uri.Query == "" ? "?" : "&") + "client_id=" + clientID); result = await wc.DownloadStringAsTask(uri, cancel, progress); } else { var sb = new StringBuilder(); wc.Headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"; wc.Encoding = Encoding.UTF8; if (postData != null) { if (useClientID) { postData["client_id"] = clientID; } foreach (var kvp in postData) { if (sb.Length > 0) { sb.Append('&'); } sb.Append(kvp.Key).Append('=').Append(Uri.EscapeDataString(kvp.Value)); } } result = await wc.UploadStringAsTask(new Uri(ServiceUri, endPoint), requestType.ToString().ToUpperInvariant(), sb.ToString(), cancel, progress); } JsonValue json = null; // In case of HTTP status 204 (no content). This is produced, for example, as the result of // a DELETE call to an endpoint. if (!string.IsNullOrWhiteSpace(result)) { json = JsonValue.Parse(new StringReader(result)); } return(json); } catch (WebException e) { // The Quizlet API returns a JSON document explaining the error if there is one, // so try to use that if possible. try { if (e.Response != null) { var response = (e.Response as HttpWebResponse).GetResponseStream(); using (var reader = new StreamReader(response)) { var dict = JsonDictionary.FromValue(JsonValue.Parse(reader)); var ctx = new JsonContext(); var errorCode = ctx.FromJson <string>(dict["error"]); var errorText = ctx.FromJson <string>(dict["error_description"]); if (errorCode != null && errorText != null) { switch (errorCode) { case "invalid_access": throw new AccessDeniedException(errorText); case "item_not_found": throw new ItemNotFoundException(errorText); case "item_deleted": throw new ItemDeletedException(errorText); default: throw new QuizletException(errorText); } } } } throw new QuizletException(string.Format("Unable to contact the Quizlet server ({0}).", e.Message), e); } catch (FormatException) { // Not JSON or invalid - just wrap the original exception throw new QuizletException(e.Message, e); } catch (KeyNotFoundException) { throw new QuizletException(e.Message, e); } } }