using System; using System.Net; using System.Security.Authentication; using System.Text; using Newtonsoft.Json.Linq; using RedditSharp.Things; namespace RedditSharp { public class AuthProvider { private const string AccessUrl = "https://ssl.reddit.com/api/v1/access_token"; private const string OauthGetMeUrl = "https://oauth.reddit.com/api/v1/me"; public static string OAuthToken { get; set; } public static string RefreshToken { get; set; } [Flags] public enum Scope { none = 0x0, identity = 0x1, edit = 0x2, flair = 0x4, history = 0x8, modconfig = 0x10, modflair = 0x20, modlog = 0x40, modposts = 0x80, modwiki = 0x100, mysubreddits = 0x200, privatemessages = 0x400, read = 0x800, report = 0x1000, save = 0x2000, submit = 0x4000, subscribe = 0x8000, vote = 0x10000, wikiedit = 0x20000, wikiread = 0x40000 } private readonly IWebAgent _webAgent; private readonly string _redirectUri; private readonly string _clientId; private readonly string _clientSecret; /// /// Allows use of reddit's OAuth interface, using an app set up at https://ssl.reddit.com/prefs/apps/. /// /// Granted by reddit as part of app. /// Granted by reddit as part of app. /// Selected as part of app. Reddit will send users back here. public AuthProvider(string clientId, string clientSecret, string redirectUri) { _clientId = clientId; _clientSecret = clientSecret; _redirectUri = redirectUri; _webAgent = new WebAgent(); } /// /// Creates the reddit OAuth2 Url to redirect the user to for authorization. /// /// Used to verify that the user received is the user that was sent /// Determines what actions can be performed against the user. /// Set to true for access lasting longer than one hour. /// public string GetAuthUrl(string state, Scope scope, bool permanent = false) { return String.Format("https://ssl.reddit.com/api/v1/authorize?client_id={0}&response_type=code&state={1}&redirect_uri={2}&duration={3}&scope={4}", _clientId, state, _redirectUri, permanent ? "permanent" : "temporary", scope.ToString().Replace(" ","")); } /// /// Gets the OAuth token for the user associated with the provided code. /// /// Sent by reddit as a parameter in the return uri. /// Set to true for refresh requests. /// public string GetOAuthToken(string code, bool isRefresh = false) { if (Type.GetType("Mono.Runtime") != null) ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true; _webAgent.Cookies = new CookieContainer(); var request = _webAgent.CreatePost(AccessUrl); request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + ":" + _clientSecret)); var stream = request.GetRequestStream(); if (isRefresh) { _webAgent.WritePostBody(stream, new { grant_type = "refresh_token", refresh_token = code }); } else { _webAgent.WritePostBody(stream, new { grant_type = "authorization_code", code, redirect_uri = _redirectUri }); } stream.Close(); var json = _webAgent.ExecuteRequest(request); if (json["access_token"] != null) { if (json["refresh_token"] != null) RefreshToken = json["refresh_token"].ToString(); OAuthToken = json["access_token"].ToString(); return json["access_token"].ToString(); } throw new AuthenticationException("Could not log in."); } /// /// Gets the OAuth token for the user. /// /// The username. /// The user's password. /// The access token public string GetOAuthToken(string username, string password) { if (Type.GetType("Mono.Runtime") != null) ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true; _webAgent.Cookies = new CookieContainer(); var request = _webAgent.CreatePost(AccessUrl); request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + ":" + _clientSecret)); var stream = request.GetRequestStream(); _webAgent.WritePostBody(stream, new { grant_type = "password", username, password, redirect_uri = _redirectUri }); stream.Close(); var json = _webAgent.ExecuteRequest(request); if (json["access_token"] != null) { if (json["refresh_token"] != null) RefreshToken = json["refresh_token"].ToString(); OAuthToken = json["access_token"].ToString(); return json["access_token"].ToString(); } throw new AuthenticationException("Could not log in."); } /// /// Gets a user authenticated by OAuth2. /// /// Obtained using GetOAuthToken /// [Obsolete("Reddit.InitOrUpdateUser is preferred")] public AuthenticatedUser GetUser(string accessToken) { var request = _webAgent.CreateGet(OauthGetMeUrl); request.Headers["Authorization"] = String.Format("bearer {0}", accessToken); var response = (HttpWebResponse)request.GetResponse(); var result = _webAgent.GetResponseString(response.GetResponseStream()); var thingjson = "{\"kind\": \"t2\", \"data\": " + result + "}"; var json = JObject.Parse(thingjson); return new AuthenticatedUser().Init(new Reddit(), json, _webAgent); } } }