Skip to content

Commit

Permalink
Add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
frederikprijck committed Oct 26, 2023
1 parent 1af30f2 commit d819e8c
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 102 deletions.
2 changes: 1 addition & 1 deletion nuget/Auth0.OidcClient.MAUI.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>Auth0.OidcClient.MAUI</id>
<version>1.0.0-beta.1</version>
<version>1.0.0-beta.0</version>
<authors>Auth0</authors>
<owners>Auth0</owners>
<license type="expression">Apache-2.0</license>
Expand Down
53 changes: 30 additions & 23 deletions src/Auth0.OidcClient.MAUI.Platforms.Windows/Activator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,54 @@

namespace Auth0.OidcClient.Platforms.Windows
{
public sealed class Activator
public interface IActivator
{
internal static bool RedirectActivationCheck;
bool RedirectActivationChecked { get; }
bool CheckRedirectionActivation();
}

/// <summary>
/// Activator class used to enable protocol activation check and redirects activation to the correct application instance
/// </summary>
public sealed class Activator : IActivator
{
private readonly IAppInstanceProxy _appInstanceProxy;

public static readonly Activator Default = new Activator(new AppInstanceProxy());

internal Activator(IAppInstanceProxy appInstanceProxy)
{
_appInstanceProxy = appInstanceProxy;
}

/// <summary>
/// Performs an protocol activation check and redirects activation to the correct application instance.
/// Boolean indication the redirect activation was checked
/// </summary>
public static bool CheckRedirectionActivation()
public bool RedirectActivationChecked { get; internal set; }

/// <summary>
/// Performs a protocol activation check and redirects activation to the correct application instance.
/// </summary>
public bool CheckRedirectionActivation()
{
var activatedEventArgs = AppInstance.GetCurrent()?.GetActivatedEventArgs();
var activatedEventArgs = _appInstanceProxy.GetCurrentActivatedEventArgs();

RedirectActivationCheck = true;
RedirectActivationChecked = true;

if (activatedEventArgs is null || activatedEventArgs.Kind != ExtendedActivationKind.Protocol || activatedEventArgs.Data is not IProtocolActivatedEventArgs protocolArgs)
{
return false;
}

var ctx = RedirectionContextManager.GetRedirectionContext(activatedEventArgs.Data as IProtocolActivatedEventArgs);
var ctx = RedirectionContextManager.GetRedirectionContext(protocolArgs);

if (ctx is not null && ctx.AppInstanceKey is not null && ctx.TaskId is not null)
{
var instance = AppInstance.GetInstances().FirstOrDefault(i => i.Key == ctx.AppInstanceKey);

if (instance is not null && !instance.IsCurrent)
{
instance.RedirectActivationToAsync(activatedEventArgs).AsTask().Wait();

System.Diagnostics.Process.GetCurrentProcess().Kill();

return true;
}
return _appInstanceProxy.RedirectActivationToAsync(ctx.AppInstanceKey, activatedEventArgs);
}
else
{
var instance = AppInstance.GetCurrent();

if (string.IsNullOrEmpty(instance.Key))
{
AppInstance.FindOrRegisterForKey(Guid.NewGuid().ToString());
}
_appInstanceProxy.FindOrRegisterForKey();
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Windows.AppLifecycle;

namespace Auth0.OidcClient.Platforms.Windows;

internal interface IAppActivationArguments
{
ExtendedActivationKind Kind { get; set; }
object Data { get; set; }
}

internal class AppActivationArguments : IAppActivationArguments
{
public ExtendedActivationKind Kind { get; set; }
public object Data { get; set; }
}
70 changes: 60 additions & 10 deletions src/Auth0.OidcClient.MAUI.Platforms.Windows/AppInstanceProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,12 @@ internal interface IAppInstanceProxy
{
event EventHandler<IAppActivationArguments> Activated;
string GetCurrentAppKey();
}
Microsoft.Windows.AppLifecycle.AppActivationArguments GetCurrentActivatedEventArgs();

internal interface IAppActivationArguments
{
ExtendedActivationKind Kind { get; set; }
object Data { get; set; }
}
bool RedirectActivationToAsync(string key,
Microsoft.Windows.AppLifecycle.AppActivationArguments activatedEventArgs);

internal class AppActivationArguments : IAppActivationArguments
{
public ExtendedActivationKind Kind { get; set; }
public object Data { get; set; }
void FindOrRegisterForKey();
}

/// <summary>
Expand All @@ -43,8 +37,64 @@ protected virtual void OnActivated(object? sender, Microsoft.Windows.AppLifecycl
});
}

/// <summary>
/// Get the current application key.
/// </summary>
/// <remarks>
/// Proxy call to AppInstance.GetCurrent().Key.
/// Used because AppInstance is complicated to use in tests.
/// </remarks>
/// <returns>The key for the current application.</returns>
public virtual string GetCurrentAppKey()
{
return AppInstance.GetCurrent().Key;
}

/// <summary>
/// Get the current application <see cref="AppActivationArguments"/>
/// </summary>
/// <remarks>
/// Proxy call to AppInstance.GetCurrent().GetActivatedEventArgs().
/// Used because AppInstance is complicated to use in tests.
/// </remarks>
/// <returns>Null if no current application instance is found, or the corresponding <see cref="AppActivationArguments"/>.</returns>
public virtual Microsoft.Windows.AppLifecycle.AppActivationArguments GetCurrentActivatedEventArgs()
{
return AppInstance.GetCurrent()?.GetActivatedEventArgs();
}

/// <summary>
/// Redirect the activation to the correct application instance and kill the current process.
/// </summary>
/// <param name="key">Key of the application to activated</param>
/// <param name="activatedEventArgs"><see cref="AppActivationArguments"/> to pass to the application.</param>
/// <returns>Boolean indicating an application instance was activated.</returns>
public virtual bool RedirectActivationToAsync(string key, Microsoft.Windows.AppLifecycle.AppActivationArguments activatedEventArgs)
{
var instance = AppInstance.GetInstances().FirstOrDefault(i => i.Key == key);

if (instance is not null && !instance.IsCurrent)
{
instance.RedirectActivationToAsync(activatedEventArgs).AsTask().Wait();

System.Diagnostics.Process.GetCurrentProcess().Kill();

return true;
}

return false;
}

/// <summary>
/// Registers the current application using a new key.
/// </summary>
public virtual void FindOrRegisterForKey()
{
var instance = AppInstance.GetCurrent();

if (string.IsNullOrEmpty(instance.Key))
{
AppInstance.FindOrRegisterForKey(Guid.NewGuid().ToString());
}
}
}
20 changes: 20 additions & 0 deletions src/Auth0.OidcClient.MAUI.Platforms.Windows/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal interface IHelpers
bool IsUriProtocolDeclared(string scheme);
void OpenBrowser(Uri uri);
}

internal class Helpers : IHelpers
{
#pragma warning disable SA1203 // Constants should appear before fields
Expand All @@ -21,6 +22,13 @@ internal class Helpers : IHelpers
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, System.Text.StringBuilder packageFullName);

/// <summary>
/// Helper property to verify the application is packaged.
/// </summary>
/// <remarks>
/// Original source: https://github.com/dotMorten/WinUIEx
/// </remarks>
/// <returns>A boolean indicate whether or not the app is packaged.</returns>
public bool IsAppPackaged
{
get
Expand All @@ -40,6 +48,14 @@ public bool IsAppPackaged
}
}

/// <summary>
/// Helper method to verify the scheme is defined as a protocol in the AppxManifest.xml files
/// </summary>
/// <remarks>
/// Original source: https://github.com/dotMorten/WinUIEx
/// </remarks>
/// <param name="scheme">The scheme expected to be declared.</param>
/// <returns>A boolean indicate whether or not the scheme is declared as an Uri protocol.</returns>
public bool IsUriProtocolDeclared(string scheme)
{
if (global::Windows.ApplicationModel.Package.Current is null)
Expand All @@ -57,6 +73,10 @@ public bool IsUriProtocolDeclared(string scheme)
return decl != null && decl.Any();
}

/// <summary>
/// Helper method to open the browser through the url.dll.
/// </summary>
/// <param name="uri">The Uri to open</param>
public void OpenBrowser(Uri uri)
{
var process = new System.Diagnostics.Process();
Expand Down
17 changes: 17 additions & 0 deletions src/Auth0.OidcClient.MAUI.Platforms.Windows/RedirectionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@ namespace Auth0.OidcClient.Platforms.Windows
{
internal class RedirectionContext
{
/// <summary>
/// The id of the task associated with the current redirect.
/// </summary>
internal string TaskId { get; set; }

/// <summary>
/// The key of the application associated with the current redirect.
/// </summary>
internal string AppInstanceKey { get; set; }

/// <summary>
/// Generate a new <see cref="RedirectionContext"/> based on the application instance.
/// </summary>
/// <param name="appInstanceProxy">The current application instance.</param>
/// <returns>The newly created <see cref="RedirectionContext"/></returns>
internal static RedirectionContext New(IAppInstanceProxy appInstanceProxy)
{
return new RedirectionContext
Expand All @@ -17,6 +29,11 @@ internal static RedirectionContext New(IAppInstanceProxy appInstanceProxy)
};
}

/// <summary>
/// Converts the <see cref="RedirectionContext"/> to a <see cref="JsonObject"/> for serialization.
/// </summary>
/// <param name="query">A <see cref="NameValueCollection"/> holding an optional state property to incorporate in the <see cref="JsonObject"/>.</param>
/// <returns></returns>
internal JsonObject ToJsonObject(NameValueCollection query)
{
var jsonObject = new JsonObject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ namespace Auth0.OidcClient.Platforms.Windows
{
internal class RedirectionContextManager
{
/// <summary>
/// Gets the <see cref="RedirectionContext"/> from the provided <see cref="IProtocolActivatedEventArgs"/>
/// </summary>
/// <param name="protocolArgs">The event arguments associated with the corresponding protocol activation.</param>
/// <returns>The newly created <see cref="RedirectionContext"/>.</returns>
internal static RedirectionContext? GetRedirectionContext(IProtocolActivatedEventArgs protocolArgs)
{
var vals = System.Web.HttpUtility.ParseQueryString(protocolArgs.Uri.Query);
var state = vals["state"];
var query = System.Web.HttpUtility.ParseQueryString(protocolArgs.Uri.Query);
var state = query["state"];
JsonObject jsonObject = null;

if (!string.IsNullOrEmpty(state))
Expand All @@ -26,13 +31,18 @@ internal class RedirectionContextManager
TaskId = TryGetJsonValue(jsonObject, "taskId")
};
}
else
{
return null;
}

return null;
}

private static string? TryGetJsonValue(JsonObject jsonObject, string key)

/// <summary>
/// Helper method to try and get a value from a <see cref="JsonObject"/>.
/// </summary>
/// <param name="jsonObject">The corresponding <see cref="JsonObject"/>.</param>
/// <param name="key">The key for the value to be retrieve from the <see cref="JsonObject"/></param>
/// <returns>The value from the provided key, or null if not found.</returns>
private static string TryGetJsonValue(JsonObject jsonObject, string key)
{
if (jsonObject.ContainsKey(key) && jsonObject[key] is JsonValue jValue && jValue.TryGetValue(out string value))
{
Expand Down
Loading

0 comments on commit d819e8c

Please sign in to comment.