mirror of
https://github.com/bitwarden/mobile
synced 2025-12-12 14:23:26 +00:00
* PM-6539 Fix Autofill Extension TDE without MP updating PromptSSO to work in MAUI and also Generator view. WebAuthenticator copied with UIWindow gotten as it was in Xamarin forms to work. Also fix one NRE on state migration. * PM-6539 Remove unnecessary using
126 lines
4.2 KiB
C#
126 lines
4.2 KiB
C#
// This is copied from MAUI repo to be used from WebAuthenticator
|
|
// https://github.com/dotnet/maui/blob/main/src/Essentials/src/Types/Shared/WebUtils.shared.cs
|
|
|
|
#if IOS
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
|
|
namespace Bit.Core.Utilities.MAUI
|
|
{
|
|
static class WebUtils
|
|
{
|
|
internal static IDictionary<string, string> ParseQueryString(Uri uri)
|
|
{
|
|
var parameters = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
|
|
if (uri == null)
|
|
return parameters;
|
|
|
|
// Note: Uri.Query starts with a '?'
|
|
if (!string.IsNullOrEmpty(uri.Query))
|
|
UnpackParameters(uri.Query.AsSpan(1), parameters);
|
|
|
|
// Note: Uri.Fragment starts with a '#'
|
|
if (!string.IsNullOrEmpty(uri.Fragment))
|
|
UnpackParameters(uri.Fragment.AsSpan(1), parameters);
|
|
|
|
return parameters;
|
|
}
|
|
|
|
// The following method is a port of the logic found in https://source.dot.net/#Microsoft.AspNetCore.WebUtilities/src/Shared/QueryStringEnumerable.cs
|
|
// but refactored such that it:
|
|
//
|
|
// 1. avoids the IEnumerable overhead that isn't needed (the ASP.NET logic was clearly designed that way to offer a public API whereas we don't need that)
|
|
// 2. avoids the use of unsafe code
|
|
static void UnpackParameters(ReadOnlySpan<char> query, Dictionary<string, string> parameters)
|
|
{
|
|
while (!query.IsEmpty)
|
|
{
|
|
int delimeterIndex = query.IndexOf('&');
|
|
ReadOnlySpan<char> segment;
|
|
|
|
if (delimeterIndex >= 0)
|
|
{
|
|
segment = query.Slice(0, delimeterIndex);
|
|
query = query.Slice(delimeterIndex + 1);
|
|
}
|
|
else
|
|
{
|
|
segment = query;
|
|
query = default;
|
|
}
|
|
|
|
// If it's nonempty, emit it
|
|
if (!segment.IsEmpty)
|
|
{
|
|
var equalIndex = segment.IndexOf('=');
|
|
string name, value;
|
|
|
|
if (equalIndex >= 0)
|
|
{
|
|
name = segment.Slice(0, equalIndex).ToString();
|
|
|
|
var span = segment.Slice(equalIndex + 1);
|
|
var chars = new char[span.Length];
|
|
|
|
for (int i = 0; i < span.Length; i++)
|
|
chars[i] = span[i] == '+' ? ' ' : span[i];
|
|
|
|
value = new string(chars);
|
|
}
|
|
else
|
|
{
|
|
name = segment.ToString();
|
|
value = string.Empty;
|
|
}
|
|
|
|
name = Uri.UnescapeDataString(name);
|
|
|
|
parameters[name] = Uri.UnescapeDataString(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static Uri EscapeUri(Uri uri)
|
|
{
|
|
if (uri == null)
|
|
throw new ArgumentNullException(nameof(uri));
|
|
|
|
var idn = new global::System.Globalization.IdnMapping();
|
|
return new Uri(uri.Scheme + "://" + idn.GetAscii(uri.Authority) + uri.PathAndQuery + uri.Fragment);
|
|
}
|
|
|
|
internal static bool CanHandleCallback(Uri expectedUrl, Uri callbackUrl)
|
|
{
|
|
if (!callbackUrl.Scheme.Equals(expectedUrl.Scheme, StringComparison.OrdinalIgnoreCase))
|
|
return false;
|
|
|
|
if (!string.IsNullOrEmpty(expectedUrl.Host))
|
|
{
|
|
if (!callbackUrl.Host.Equals(expectedUrl.Host, StringComparison.OrdinalIgnoreCase))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if __IOS__ || __TVOS__ || __MACOS__
|
|
internal static Foundation.NSUrl GetNativeUrl(Uri uri)
|
|
{
|
|
try
|
|
{
|
|
return new Foundation.NSUrl(uri.OriginalString);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Unable to create NSUrl from Original string, trying Absolute URI: {ex.Message}");
|
|
return new Foundation.NSUrl(uri.AbsoluteUri);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#endif |