|
@@ -0,0 +1,149 @@
|
|
|
+using System.Text;
|
|
|
+using Logging.Net;
|
|
|
+using Moonlight.App.Database.Entities;
|
|
|
+using Moonlight.App.Exceptions;
|
|
|
+using Moonlight.App.Models.Google.Requests;
|
|
|
+using RestSharp;
|
|
|
+
|
|
|
+namespace Moonlight.App.Services.OAuth2;
|
|
|
+
|
|
|
+public class GoogleOAuth2Service
|
|
|
+{
|
|
|
+ private readonly bool EnableGoogle;
|
|
|
+ private readonly string GoogleClientId;
|
|
|
+ private readonly string GoogleClientSecret;
|
|
|
+
|
|
|
+ private readonly bool EnableOverrideUrl;
|
|
|
+ private readonly string OverrideUrl;
|
|
|
+ private readonly string AppUrl;
|
|
|
+
|
|
|
+ public GoogleOAuth2Service(ConfigService configService)
|
|
|
+ {
|
|
|
+ var config = configService
|
|
|
+ .GetSection("Moonlight")
|
|
|
+ .GetSection("OAuth2");
|
|
|
+
|
|
|
+ EnableGoogle = config
|
|
|
+ .GetSection("Google")
|
|
|
+ .GetValue<bool>("Enable");
|
|
|
+
|
|
|
+ if (EnableGoogle)
|
|
|
+ {
|
|
|
+ GoogleClientId = config.GetSection("Google").GetValue<string>("ClientId");
|
|
|
+ GoogleClientSecret = config.GetSection("Google").GetValue<string>("ClientSecret");
|
|
|
+ }
|
|
|
+
|
|
|
+ EnableOverrideUrl = config.GetValue<bool>("EnableOverrideUrl");
|
|
|
+
|
|
|
+ if (EnableOverrideUrl)
|
|
|
+ OverrideUrl = config.GetValue<string>("OverrideUrl");
|
|
|
+
|
|
|
+ AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task<string> GetUrl()
|
|
|
+ {
|
|
|
+ if (!EnableGoogle)
|
|
|
+ throw new DisplayException("Google OAuth2 not enabled");
|
|
|
+
|
|
|
+ var endpoint = GetBaseUrl() + "/api/moonlight/oauth2/google";
|
|
|
+ var scope = "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email";
|
|
|
+
|
|
|
+ return Task.FromResult(
|
|
|
+ $"https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={GoogleClientId}&redirect_uri={endpoint}&scope={scope}"
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<User?> HandleCode(string code)
|
|
|
+ {
|
|
|
+ // Generate access token
|
|
|
+ var endpoint = GetBaseUrl() + "/api/moonlight/oauth2/google";
|
|
|
+ var googleEndpoint = "https://oauth2.googleapis.com/token";
|
|
|
+
|
|
|
+ // Setup payload
|
|
|
+ var payload = new GoogleOAuth2CodePayload()
|
|
|
+ {
|
|
|
+ Code = code,
|
|
|
+ RedirectUri = endpoint,
|
|
|
+ ClientId = GoogleClientId,
|
|
|
+ ClientSecret = GoogleClientSecret
|
|
|
+ };
|
|
|
+
|
|
|
+ using var client = new RestClient();
|
|
|
+ var request = new RestRequest(googleEndpoint);
|
|
|
+
|
|
|
+ request.AddBody(payload);
|
|
|
+ var response = await client.ExecutePostAsync(request);
|
|
|
+
|
|
|
+ if (!response.IsSuccessful)
|
|
|
+ {
|
|
|
+ //TODO: Maybe add better error handling
|
|
|
+ Logger.Debug("oAuth2 validate error: " + response.Content!);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // parse response
|
|
|
+
|
|
|
+ var data = new ConfigurationBuilder().AddJsonStream(
|
|
|
+ new MemoryStream(Encoding.ASCII.GetBytes(response.Content!))
|
|
|
+ ).Build();
|
|
|
+
|
|
|
+ var accessToken = data.GetValue<string>("access_token");
|
|
|
+
|
|
|
+ // Now, we will call the google api with our access token to get the data we need
|
|
|
+
|
|
|
+ var googlePeopleEndpoint = "https://people.googleapis.com/v1/people/me";
|
|
|
+
|
|
|
+ var getRequest = new RestRequest(googlePeopleEndpoint);
|
|
|
+ getRequest.AddHeader("Authorization", $"Bearer {accessToken}");
|
|
|
+ getRequest.AddParameter("personFields", "names,emailAddresses");
|
|
|
+
|
|
|
+ var getResponse = await client.ExecuteGetAsync(getRequest);
|
|
|
+
|
|
|
+ if (!getResponse.IsSuccessful)
|
|
|
+ {
|
|
|
+ //TODO: Maybe add better error handling
|
|
|
+ Logger.Debug("OAuth2 api access error: " + getResponse.Content!);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Parse response
|
|
|
+
|
|
|
+ var getData = new ConfigurationBuilder().AddJsonStream(
|
|
|
+ new MemoryStream(Encoding.ASCII.GetBytes(getResponse.Content!))
|
|
|
+ ).Build();
|
|
|
+
|
|
|
+ var firstName = getData
|
|
|
+ .GetSection("names")
|
|
|
+ .GetChildren()
|
|
|
+ .First()
|
|
|
+ .GetValue<string>("givenName");
|
|
|
+
|
|
|
+ var lastName = getData
|
|
|
+ .GetSection("names")
|
|
|
+ .GetChildren()
|
|
|
+ .First()
|
|
|
+ .GetValue<string>("familyName");
|
|
|
+
|
|
|
+ var email = getData
|
|
|
+ .GetSection("emailAddresses")
|
|
|
+ .GetChildren()
|
|
|
+ .First()
|
|
|
+ .GetValue<string>("value");
|
|
|
+
|
|
|
+ return new()
|
|
|
+ {
|
|
|
+ Email = email,
|
|
|
+ FirstName = firstName,
|
|
|
+ LastName = lastName
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private string GetBaseUrl()
|
|
|
+ {
|
|
|
+ if (EnableOverrideUrl)
|
|
|
+ return OverrideUrl;
|
|
|
+
|
|
|
+ return AppUrl;
|
|
|
+ }
|
|
|
+}
|