From 5f535c0929a80b3d1108430c887c401812facf76 Mon Sep 17 00:00:00 2001 From: Andy Pack Date: Sun, 21 Jan 2024 11:12:23 +0000 Subject: [PATCH] adding secrets manager and startup --- Mixonomer.Fire/Mixonomer.Fire.csproj | 1 + Mixonomer.Func/RunUserPlaylist.cs | 14 +++++ Mixonomer.Playlist/Mixonomer.Playlist.csproj | 4 ++ Mixonomer.Playlist/SecretStrings.cs | 16 ++++++ Mixonomer.Playlist/SpotifyNetworkProvider.cs | 55 ++++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 Mixonomer.Playlist/SecretStrings.cs create mode 100644 Mixonomer.Playlist/SpotifyNetworkProvider.cs diff --git a/Mixonomer.Fire/Mixonomer.Fire.csproj b/Mixonomer.Fire/Mixonomer.Fire.csproj index 9ff9b17..4130039 100644 --- a/Mixonomer.Fire/Mixonomer.Fire.csproj +++ b/Mixonomer.Fire/Mixonomer.Fire.csproj @@ -11,5 +11,6 @@ + diff --git a/Mixonomer.Func/RunUserPlaylist.cs b/Mixonomer.Func/RunUserPlaylist.cs index 16bfd4f..7fa23f9 100644 --- a/Mixonomer.Func/RunUserPlaylist.cs +++ b/Mixonomer.Func/RunUserPlaylist.cs @@ -4,12 +4,16 @@ using System.Threading; using System.Threading.Tasks; using CloudNative.CloudEvents; using Google.Cloud.Functions.Framework; +using Google.Cloud.Functions.Hosting; using Google.Events.Protobuf.Cloud.PubSub.V1; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Mixonomer.Fire; namespace Mixonomer.Func; +[FunctionsStartup(typeof(RunUserPlaylistStartup))] public class RunUserPlaylist : ICloudEventFunction { private readonly ILogger _logger; @@ -30,4 +34,14 @@ public class RunUserPlaylist : ICloudEventFunction _logger.LogInformation($"{user.username} was last refreshed at {user.last_refreshed}"); } +} + +public class RunUserPlaylistStartup : FunctionsStartup +{ + public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) + { + base.ConfigureServices(context, services); + + services.AddSecretManagerServiceClient(); + } } \ No newline at end of file diff --git a/Mixonomer.Playlist/Mixonomer.Playlist.csproj b/Mixonomer.Playlist/Mixonomer.Playlist.csproj index e613689..ad629e8 100644 --- a/Mixonomer.Playlist/Mixonomer.Playlist.csproj +++ b/Mixonomer.Playlist/Mixonomer.Playlist.csproj @@ -11,4 +11,8 @@ + + + + diff --git a/Mixonomer.Playlist/SecretStrings.cs b/Mixonomer.Playlist/SecretStrings.cs new file mode 100644 index 0000000..fac477b --- /dev/null +++ b/Mixonomer.Playlist/SecretStrings.cs @@ -0,0 +1,16 @@ +namespace Mixonomer.Playlist; + +public static class SecretStrings +{ + public static Lazy GoogleProject = new(() => Environment.GetEnvironmentVariable("GOOGLE_CLOUD_PROJECT") ?? + throw new ArgumentException("no GOOGLE_CLOUD_PROJECT env variable available")); + + public static string SPOT_CLIENT_URI => $"projects/{GoogleProject.Value}/secrets/spotify-client/versions/latest"; + public static string SPOT_SECRET_URI => $"projects/{GoogleProject.Value}/secrets/spotify-secret/versions/latest"; + public static string LASTFM_CLIENT_URI => $"projects/{GoogleProject.Value}/secrets/lastfm-client/versions/latest"; + public static string JWT_SECRET_URI => $"projects/{GoogleProject.Value}/secrets/jwt-secret/versions/latest"; + public static string COOKIE_SECRET_URI => $"projects/{GoogleProject.Value}/secrets/cookie-secret/versions/latest"; + public static string APNS_SIGN_URI => $"projects/{GoogleProject.Value}/secrets/apns-auth-sign-key/versions/1"; + + public static string STATIC_BUCKET => $"{GoogleProject.Value}-static"; +} \ No newline at end of file diff --git a/Mixonomer.Playlist/SpotifyNetworkProvider.cs b/Mixonomer.Playlist/SpotifyNetworkProvider.cs new file mode 100644 index 0000000..92ac05c --- /dev/null +++ b/Mixonomer.Playlist/SpotifyNetworkProvider.cs @@ -0,0 +1,55 @@ +using Google.Cloud.SecretManager.V1; +using Mixonomer.Fire; +using SpotifyAPI.Web; + +namespace Mixonomer.Playlist; + +public class SpotifyNetworkProvider +{ + private readonly SecretManagerServiceClient _secretClient; + private readonly UserRepo _userRepo; + + public SpotifyNetworkProvider(UserRepo userRepo, SecretManagerServiceClient secretClient) + { + _userRepo = userRepo; + _secretClient = secretClient ?? SecretManagerServiceClient.Create(); + } + + public async Task GetUserConfig(string username) + { + return await GetUserConfig(await _userRepo.GetUser(username)); + } + + public async Task GetUserConfig(User user) + { + var spotifyClient = await _secretClient.AccessSecretVersionAsync(SecretStrings.SPOT_CLIENT_URI); + var spotifySecret = await _secretClient.AccessSecretVersionAsync(SecretStrings.SPOT_SECRET_URI); + + var spotifyClientStr = spotifyClient.Payload.Data.ToString() ?? throw new ArgumentException("No Spotify Client ID returned"); + var spotifySecretStr = spotifySecret.Payload.Data.ToString() ?? throw new ArgumentException("No Spotify Secret ID returned"); + + var refreshed = await new OAuthClient() + .RequestToken(new AuthorizationCodeRefreshRequest(spotifyClientStr, spotifySecretStr, user.refresh_token)); + + var authenticator = new AuthorizationCodeAuthenticator(spotifyClientStr, spotifySecretStr, new() + { + AccessToken = refreshed.AccessToken, + TokenType = refreshed.TokenType, + ExpiresIn = refreshed.ExpiresIn, + Scope = refreshed.Scope, + RefreshToken = refreshed.RefreshToken ?? user.refresh_token, + CreatedAt = refreshed.CreatedAt + }); + + authenticator.TokenRefreshed += (sender, resp) => + { + + }; + + var config = SpotifyClientConfig + .CreateDefault() + .WithAuthenticator(authenticator); + + return config; + } +} \ No newline at end of file