Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update AuthFunction.cs #1343

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 38 additions & 76 deletions Auth/AuthFunction.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Auth.Extensions;
using Auth.Model;
using Common.TableModels;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Newtonsoft.Json;

namespace Auth
{
public static class AuthFunction
{
public static readonly string Webhost = "https://imgbot.net";
private static readonly HttpClient HttpClient = new HttpClient();
private static readonly string WebHost = "https://imgbot.net";
private static readonly string GithubAuthorizeUrl = "https://github.com/login/oauth/authorize";
private static readonly string GithubAccessTokenUrl = "https://github.com/login/oauth/access_token";
private static readonly string GithubUserUrl = "https://api.github.com/user";
private static readonly string GithubMarketplaceUrl = "https://api.github.com/user/marketplace_purchases";
private static readonly string GithubEducationUrl = "https://education.github.com/api/user";

[FunctionName("SetupFunction")]
public static HttpResponseMessage Setup(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "setup")]HttpRequestMessage req,
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "setup")] HttpRequestMessage req,
ExecutionContext executionContext)
{
var secrets = Secrets.Get(executionContext);
Expand All @@ -33,16 +32,13 @@ public static HttpResponseMessage Setup(
state += ",fromapp";
}

var response = req.CreateResponse();
response
.SetCookie("state", state)
.SetRedirect($"https://github.com/login/oauth/authorize?client_id={secrets.ClientId}&redirect_uri={secrets.RedirectUri}&state={state}");
return response;
var authorizeUrl = $"{GithubAuthorizeUrl}?client_id={secrets.ClientId}&redirect_uri={secrets.RedirectUri}&state={state}";
return req.CreateResponse().SetCookie("state", state).SetRedirect(authorizeUrl);
}

[FunctionName("CallbackFunction")]
public static async Task<HttpResponseMessage> Callback(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "callback")]HttpRequestMessage req,
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "callback")] HttpRequestMessage req,
ExecutionContext executionContext,
ILogger logger)
{
Expand All @@ -53,10 +49,9 @@ public static async Task<HttpResponseMessage> Callback(
var marketplaceTable = storageAccount.CreateCloudTableClient().GetTableReference("marketplace");

var stateCookie = req.ReadCookie("state");

if (string.IsNullOrEmpty(stateCookie))
{
logger.LogError("state cookie is missing");
logger.LogError("State cookie is missing");
return Winning(req);
}

Expand All @@ -66,24 +61,24 @@ public static async Task<HttpResponseMessage> Callback(

if (stateQuery != stateCookie)
{
logger.LogError("state mismatch: {StateCookie} !== {StateQuery}", stateCookie, stateQuery);
logger.LogError("State mismatch: {StateCookie} !== {StateQuery}", stateCookie, stateQuery);
return Winning(req);
}

if (string.IsNullOrEmpty(code))
{
logger.LogError("code is missing");
logger.LogError("Code is missing");
return Winning(req);
}

var tokenResponse = await HttpClient.PostAsJsonAsync("https://github.com/login/oauth/access_token", new
var tokenResponse = await HttpClient.PostAsync(GithubAccessTokenUrl, new FormUrlEncodedContent(new[]
{
client_id = secrets.ClientId,
client_secret = secrets.ClientSecret,
code,
redirect_uri = secrets.RedirectUri,
state = stateQuery
});
new KeyValuePair<string, string>("client_id", secrets.ClientId),
new KeyValuePair<string, string>("client_secret", secrets.ClientSecret),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", secrets.RedirectUri),
new KeyValuePair<string, string>("state", stateQuery)
}));

var tokenContent = await tokenResponse.Content.ReadAsFormDataAsync();
if (tokenContent.Get("error") != null)
Expand All @@ -94,31 +89,14 @@ public static async Task<HttpResponseMessage> Callback(

var token = tokenContent.Get("access_token");

var mktplcRequest = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user/marketplace_purchases");
mktplcRequest.Headers.Add("User-Agent", "IMGBOT");
mktplcRequest.Headers.Authorization = new AuthenticationHeaderValue("token", token);
var mktplcResponse = await HttpClient.SendAsync(mktplcRequest);
var mktplcResponse = await HttpClient.GetAsync($"{GithubMarketplaceUrl}?access_token={token}");
var planDataJson = await mktplcResponse.Content.ReadAsStringAsync();
var planData = JsonConvert.DeserializeObject<PlanData[]>(planDataJson);
var eduData = new Edu();
var isStudent = false;
try
{
var eduRequest = new HttpRequestMessage(HttpMethod.Get, "https://education.github.com/api/user");
eduRequest.Headers.Add("User-Agent", "IMGBOT");
eduRequest.Headers.Add("Authorization", "token " + token);
var eduResponse = await HttpClient.SendAsync(eduRequest);
var eduDataJson = await eduResponse.Content.ReadAsStringAsync();
eduData = JsonConvert.DeserializeObject<Edu>(eduDataJson);
if (eduData != null)
{
isStudent = eduData.Student;
}
}
catch (Exception e)
{
logger.LogError(e, "Error processing auth education");
}

var eduResponse = await HttpClient.GetAsync($"{GithubEducationUrl}?access_token={token}");
var eduDataJson = await eduResponse.Content.ReadAsStringAsync();
var eduData = JsonConvert.DeserializeObject<Edu>(eduDataJson);
var isStudent = eduData?.Student ?? false;

foreach (var item in planData)
{
Expand All @@ -132,20 +110,16 @@ public static async Task<HttpResponseMessage> Callback(
await marketplaceTable.ExecuteAsync(TableOperation.InsertOrMerge(marketplaceRow));
}

if (planData.Length == 0 && eduData.Student == true)
if (planData.Length == 0 && isStudent)
{
// no marketplace data so we need to get the account id from the user api
var userRequest = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user");
userRequest.Headers.Add("User-Agent", "IMGBOT");
userRequest.Headers.Add("Authorization", "token " + token);
var userResponse = await HttpClient.SendAsync(userRequest);
var userResponse = await HttpClient.GetAsync($"{GithubUserUrl}?access_token={token}");
var userDataJson = await userResponse.Content.ReadAsStringAsync();
var userData = JsonConvert.DeserializeObject<Account>(userDataJson);
var marketplaceRow = new Marketplace(userData.id, userData.login)
{
AccountType = userData.type,
PlanId = 1337,
Student = eduData.Student,
Student = isStudent,
};

await marketplaceTable.CreateIfNotExistsAsync();
Expand All @@ -162,48 +136,36 @@ public static async Task<HttpResponseMessage> Callback(
return Winning(req);
}

public static HttpResponseMessage Winning(HttpRequestMessage req, string token = null, string state = null)
private static HttpResponseMessage Winning(HttpRequestMessage req, string token = null, string state = null)
{
var response = req.CreateResponse();
if (token != null)
{
response.SetCookie("token", token);
}

if (state != null && state.Contains(",") && state.Split(',')[1] == "fromapp")
{
response.SetRedirect(Webhost + "/app");
}
else
{
response.SetRedirect(Webhost + "/winning");
}
var redirectUrl = state?.Contains(",fromapp") == true ? $"{WebHost}/app" : $"{WebHost}/winning";
response.SetRedirect(redirectUrl);

return response;
}

[FunctionName("IsAuthenticatedFunction")]
public static HttpResponseMessage IsAuthenticated(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "isauthenticated")]HttpRequestMessage req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "isauthenticated")] HttpRequestMessage req)
{
var tokenCookie = req.ReadCookie("token");
var response = req.CreateResponse();
response.StatusCode = HttpStatusCode.OK;
response
.SetJson(new { result = !string.IsNullOrEmpty(tokenCookie) })
.EnableCors();
return response;
var isAuthenticated = !string.IsNullOrEmpty(tokenCookie);
return req.CreateResponse().SetJson(new { result = isAuthenticated }).EnableCors();
}

[FunctionName("SignoutFunction")]
public static HttpResponseMessage Signout(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "signout")]HttpRequestMessage req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "signout")] HttpRequestMessage req)
{
var response = req
.CreateResponse()
return req.CreateResponse()
.SetCookie("token", "rubbish", new DateTime(1970, 1, 1))
.SetRedirect(Webhost + "/app");
return response;
.SetRedirect($"{WebHost}/app");
}
}
}