Bitwarden-app-android-iphon.../src/App/Pages/CaptchaProtectedViewModel.cs

89 lines
3.4 KiB
C#
Raw Normal View History

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Newtonsoft.Json;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public abstract class CaptchaProtectedViewModel : BaseViewModel
{
protected abstract II18nService i18nService { get; }
protected abstract IEnvironmentService environmentService { get; }
protected abstract IDeviceActionService deviceActionService { get; }
protected abstract IPlatformUtilsService platformUtilsService { get; }
protected string _captchaToken = null;
protected async Task<bool> HandleCaptchaAsync(string CaptchaSiteKey)
{
var callbackUri = "bitwarden://captcha-callback";
var data = EncodeDataParameter(new
{
siteKey = CaptchaSiteKey,
locale = i18nService.Culture.TwoLetterISOLanguageName,
callbackUri = callbackUri,
captchaRequiredText = AppResources.CaptchaRequired,
});
2021-08-12 15:23:02 +02:00
var url = environmentService.GetWebVaultUrl() + "/captcha-mobile-connector.html?" + "data=" + data +
"&parent=" + Uri.EscapeDataString(callbackUri) + "&v=1";
WebAuthenticatorResult authResult = null;
bool cancelled = false;
try
{
authResult = await WebAuthenticator.AuthenticateAsync(new Uri(url),
new Uri(callbackUri));
}
catch (TaskCanceledException)
{
await deviceActionService.HideLoadingAsync();
cancelled = true;
}
catch (Exception e)
{
// WebAuthenticator throws NSErrorException if iOS flow is cancelled - by setting cancelled to true
// here we maintain the appearance of a clean cancellation (we don't want to do this across the board
// because we still want to present legitimate errors). If/when this is fixed, we can remove this
// particular catch block (catching taskCanceledException above must remain)
// https://github.com/xamarin/Essentials/issues/1240
if (Device.RuntimePlatform == Device.iOS)
{
await deviceActionService.HideLoadingAsync();
cancelled = true;
}
}
if (cancelled == false && authResult != null &&
authResult.Properties.TryGetValue("token", out _captchaToken))
{
return true;
}
else
{
await platformUtilsService.ShowDialogAsync(AppResources.CaptchaFailed,
AppResources.CaptchaRequired);
return false;
}
}
private string EncodeDataParameter(object obj)
{
string EncodeMultibyte(Match match)
{
return Convert.ToChar(Convert.ToUInt32($"0x{match.Groups[1].Value}", 16)).ToString();
}
var escaped = Uri.EscapeDataString(JsonConvert.SerializeObject(obj));
var multiByteEscaped = Regex.Replace(escaped, "%([0-9A-F]{2})", EncodeMultibyte);
return Convert.ToBase64String(Encoding.UTF8.GetBytes(multiByteEscaped));
}
}
}