mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-26 03:59:34 +08:00
fix Android Guide Pages Test API 31 🆗
This commit is contained in:
@@ -2,33 +2,54 @@ using Android.Runtime;
|
||||
using Java.Security.Cert;
|
||||
using System.IO;
|
||||
using Xamarin.Android.Net;
|
||||
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System
|
||||
{
|
||||
public static partial class HttpClientExtensions
|
||||
{
|
||||
const string certificateFileType = "X.509";
|
||||
|
||||
static readonly Lazy<CertificateFactory?> certificateFactory = new(() =>
|
||||
{
|
||||
var certificateFactory = CertificateFactory.GetInstance(certificateFileType);
|
||||
return certificateFactory;
|
||||
});
|
||||
|
||||
internal static CertificateFactory CertificateFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
var certificateFactory = HttpClientExtensions.certificateFactory.Value;
|
||||
if (certificateFactory == null)
|
||||
throw new NullReferenceException(
|
||||
$"CertificateFactory.GetInstance Fail, Type: {certificateFileType}");
|
||||
return certificateFactory;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加可信任证书,可用于调试时HTTPS抓包
|
||||
/// </summary>
|
||||
/// <param name="handler"></param>
|
||||
/// <param name="certificateFileData">证书文件数据(文件流,内嵌资源流)</param>
|
||||
/// <param name="certificateFileType">证书文件类型,默认使用X.509</param>
|
||||
public static void AddTrustedCert(
|
||||
this AndroidClientHandler handler,
|
||||
Stream certificateFileData,
|
||||
string certificateFileType = "X.509")
|
||||
Stream certificateFileData)
|
||||
{
|
||||
var certificateFactory = CertificateFactory.GetInstance(certificateFileType);
|
||||
if (certificateFactory == null)
|
||||
throw new NullReferenceException(
|
||||
$"CertificateFactory.GetInstance Fail, Type: {certificateFileType}");
|
||||
var certificate = certificateFactory.GenerateCertificate(certificateFileData);
|
||||
var certificate = CertificateFactory.GenerateCertificate(certificateFileData);
|
||||
if (certificate == null)
|
||||
throw new NullReferenceException("GenerateCertificate Fail");
|
||||
if (handler.TrustedCerts == null)
|
||||
handler.TrustedCerts = new JavaList<Certificate>();
|
||||
handler.TrustedCerts.Add(certificate);
|
||||
}
|
||||
|
||||
public static X509Certificate Convert(this X509Certificate2 certificate2)
|
||||
{
|
||||
using var stream = new MemoryStream(certificate2.RawData);
|
||||
return CertificateFactory.GenerateCertificate(stream)!.JavaCast<X509Certificate>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,38 +84,38 @@ namespace System.Application
|
||||
return default;
|
||||
}
|
||||
|
||||
// [Obsolete]
|
||||
// public static void StartActivity(Activity activity, Type activityType, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// viewModelType ??= viewModel.GetType();
|
||||
// var viewModel_ = Serializable.SMP(viewModelType, viewModel);
|
||||
//#if DEBUG
|
||||
// var t = Serializable.DMP(viewModelType, viewModel_);
|
||||
//#endif
|
||||
// StartActivity(activity, activityType, viewModel_);
|
||||
// }
|
||||
// [Obsolete]
|
||||
// public static void StartActivity(Activity activity, Type activityType, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// viewModelType ??= viewModel.GetType();
|
||||
// var viewModel_ = Serializable.SMP(viewModelType, viewModel);
|
||||
//#if DEBUG
|
||||
// var t = Serializable.DMP(viewModelType, viewModel_);
|
||||
//#endif
|
||||
// StartActivity(activity, activityType, viewModel_);
|
||||
// }
|
||||
|
||||
// [Obsolete]
|
||||
// public static void StartActivity(Fragment fragment, Type activityType, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// var activity = fragment.Activity;
|
||||
// if (activity == null) return;
|
||||
// StartActivity(activity, activityType, viewModel, viewModelType);
|
||||
// }
|
||||
// [Obsolete]
|
||||
// public static void StartActivity(Fragment fragment, Type activityType, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// var activity = fragment.Activity;
|
||||
// if (activity == null) return;
|
||||
// StartActivity(activity, activityType, viewModel, viewModelType);
|
||||
// }
|
||||
|
||||
// [Obsolete]
|
||||
// public static void StartActivity<TActivity>(Activity activity, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// StartActivity(activity, typeof(TActivity), viewModel, viewModelType);
|
||||
// }
|
||||
// [Obsolete]
|
||||
// public static void StartActivity<TActivity>(Activity activity, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// StartActivity(activity, typeof(TActivity), viewModel, viewModelType);
|
||||
// }
|
||||
|
||||
// [Obsolete]
|
||||
// public static void StartActivity<TActivity>(Fragment fragment, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// var activity = fragment.Activity;
|
||||
// if (activity == null) return;
|
||||
// StartActivity<TActivity>(activity, viewModel, viewModelType);
|
||||
// }
|
||||
// [Obsolete]
|
||||
// public static void StartActivity<TActivity>(Fragment fragment, object viewModel, Type? viewModelType = null)
|
||||
// {
|
||||
// var activity = fragment.Activity;
|
||||
// if (activity == null) return;
|
||||
// StartActivity<TActivity>(activity, viewModel, viewModelType);
|
||||
// }
|
||||
|
||||
public static void StartActivity<TViewModel>(Activity activity, Type activityType, TViewModel viewModel)
|
||||
{
|
||||
@@ -184,7 +184,7 @@ namespace System.Application
|
||||
return InstallApk(context, apkFile);
|
||||
}
|
||||
|
||||
public static bool InstallCertificate(Context context, string filePath, string name)
|
||||
public static Intent? GetInstallCertificateIntent(string filePath, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -193,6 +193,20 @@ namespace System.Application
|
||||
intent.PutExtra("name", name);
|
||||
intent.PutExtra("CERT", File.ReadAllBytes(filePath));
|
||||
intent.AddFlags(ActivityFlags.NewTask);
|
||||
return intent;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool InstallCertificate(Context context, string filePath, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
var intent = GetInstallCertificateIntent(filePath, name);
|
||||
if (intent == null) return false;
|
||||
context.StartActivity(intent);
|
||||
return true;
|
||||
}
|
||||
@@ -202,10 +216,16 @@ namespace System.Application
|
||||
}
|
||||
}
|
||||
|
||||
static void StartNewTaskActivity(Context context, string action)
|
||||
public static Intent GetNewTaskIntent(string action)
|
||||
{
|
||||
var intent = new Intent(action);
|
||||
intent.AddFlags(ActivityFlags.NewTask);
|
||||
return intent;
|
||||
}
|
||||
|
||||
static void StartNewTaskActivity(Context context, string action)
|
||||
{
|
||||
var intent = GetNewTaskIntent(action);
|
||||
context.StartActivity(intent);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,13 @@ namespace System.Application
|
||||
ConfigChanges.LayoutDirection |
|
||||
ConfigChanges.SmallestScreenSize;
|
||||
|
||||
public const ConfigChanges ConfigurationChangesWithOutOrientationLocale =
|
||||
ConfigChanges.ScreenSize |
|
||||
ConfigChanges.Keyboard |
|
||||
ConfigChanges.KeyboardHidden |
|
||||
ConfigChanges.ScreenLayout |
|
||||
ConfigChanges.SmallestScreenSize;
|
||||
|
||||
public const string MainTheme2 = "@style/MainTheme2";
|
||||
public const string MainTheme2_NoActionBar = "@style/MainTheme2.NoActionBar";
|
||||
public const string MainTheme2_Splash = "@style/MainTheme2.Splash";
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Java.Security;
|
||||
using Javax.Net.Ssl;
|
||||
|
||||
namespace System.Application.Services.Implementation
|
||||
{
|
||||
partial class AndroidPlatformServiceImpl
|
||||
{
|
||||
static IX509TrustManager? X509TrustManager
|
||||
{
|
||||
get
|
||||
{
|
||||
var instance = KeyStore.GetInstance("AndroidCAStore");
|
||||
if (instance == null) return null;
|
||||
instance.Load(null);
|
||||
var instance2 = TrustManagerFactory.GetInstance(TrustManagerFactory.DefaultAlgorithm);
|
||||
if (instance2 == null) return null;
|
||||
instance2.Init(instance);
|
||||
var trustManager = instance2.GetTrustManagers()?
|
||||
.Select(x => x is IX509TrustManager x509TrustManager ? x509TrustManager : null)
|
||||
.FirstOrDefault(x => x != null);
|
||||
return trustManager;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsCertificateInstalled(X509Certificate2 certificate2)
|
||||
{
|
||||
var x509TrustManager = X509TrustManager;
|
||||
if (x509TrustManager == null) return false;
|
||||
using var certificate = certificate2.Convert();
|
||||
var authType = certificate.SigAlgName;
|
||||
try
|
||||
{
|
||||
x509TrustManager.CheckServerTrusted(new[] { certificate }, authType);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IPlatformService.IsCertificateInstalled(X509Certificate2 certificate2) => IsCertificateInstalled(certificate2);
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,15 @@ namespace System.Application.Services.Native
|
||||
{
|
||||
void OnResult(Intent intent)
|
||||
=> activity.StartOrStopForegroundService<VpnService>(true);
|
||||
await IntermediateActivity.StartAsync(intent,
|
||||
requestCodeVpnService, onResult: OnResult);
|
||||
try
|
||||
{
|
||||
await IntermediateActivity.StartAsync(intent,
|
||||
requestCodeVpnService, onResult: OnResult);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ using Android.Views;
|
||||
using System.Application.Services;
|
||||
using ASettings = Android.Provider.Settings;
|
||||
using static AndroidX.Activity.Result.ActivityResultTask;
|
||||
using System.Threading.Tasks;
|
||||
using XEPlatform = Xamarin.Essentials.Platform;
|
||||
|
||||
namespace System.Application.UI.Activities
|
||||
{
|
||||
@@ -27,7 +29,7 @@ namespace System.Application.UI.Activities
|
||||
[Register(JavaPackageConstants.Activities + nameof(GuideCACertActivity))]
|
||||
[Activity(Theme = ManifestConstants.MainTheme2_NoActionBar,
|
||||
LaunchMode = LaunchMode.SingleTask,
|
||||
ConfigurationChanges = ManifestConstants.ConfigurationChanges)]
|
||||
ConfigurationChanges = ManifestConstants.ConfigurationChangesWithOutOrientationLocale)]
|
||||
internal sealed class GuideCACertActivity : BaseActivity<activity_guide_ca_cert>
|
||||
{
|
||||
protected override int? LayoutResource => Resource.Layout.activity_guide_ca_cert;
|
||||
@@ -38,9 +40,13 @@ namespace System.Application.UI.Activities
|
||||
|
||||
this.SetSupportActionBarWithNavigationClick(binding!.toolbar, true);
|
||||
|
||||
Title = string.Empty;
|
||||
|
||||
var appBarConfiguration = new AppBarConfiguration.Builder(Resource.Id.navigation_guide_export_ca_cert).Build();
|
||||
navController = ((NavHostFragment)SupportFragmentManager.FindFragmentById(Resource.Id.nav_host_fragment)).NavController;
|
||||
NavigationUI.SetupActionBarWithNavController(this, navController, appBarConfiguration);
|
||||
|
||||
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
[Register(JavaPackageConstants.Fragments + nameof(GuideExportCACertFragment))]
|
||||
@@ -53,10 +59,24 @@ namespace System.Application.UI.Activities
|
||||
return IViewModelManager.Instance.GetMainPageViewModel<CommunityProxyPageViewModel>();
|
||||
}
|
||||
|
||||
bool canInstalledCACert;
|
||||
public override void OnCreateView(View view)
|
||||
{
|
||||
base.OnCreateView(view);
|
||||
|
||||
var sdkInt = (int)Build.VERSION.SdkInt;
|
||||
canInstalledCACert = !(sdkInt > 29 || (sdkInt == 29 && Build.VERSION.PreviewSdkInt > 0));
|
||||
// com.adguard.kit.compatibility.h()
|
||||
// com.adguard.android.ui.fragments.https_ca_installation.b()
|
||||
// return com.adguard.kit.compatibility.a.h() ? super.b() : R.l.https_ca_installation_guide_install_ca;
|
||||
// Android 10+ 只能通过系统设置从存储区导入 CA 证书
|
||||
|
||||
if (canInstalledCACert)
|
||||
{
|
||||
binding!.tvDesc3.Visibility = ViewStates.Gone;
|
||||
binding!.btnDone.Text = GetString(Resource.String.guide_export_ca_cert_btn_install);
|
||||
}
|
||||
|
||||
SetOnClickListener(binding!.btnDone);
|
||||
}
|
||||
|
||||
@@ -64,7 +84,14 @@ namespace System.Application.UI.Activities
|
||||
{
|
||||
if (view.Id == Resource.Id.btnDone)
|
||||
{
|
||||
ExportCertificateFile();
|
||||
if (canInstalledCACert)
|
||||
{
|
||||
InstallCertificate();
|
||||
}
|
||||
else
|
||||
{
|
||||
ExportCertificateFile();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return base.OnClick(view);
|
||||
@@ -75,15 +102,48 @@ namespace System.Application.UI.Activities
|
||||
var isOK = await ViewModel!.ExportCertificateFileAsync();
|
||||
if (isOK)
|
||||
{
|
||||
GoToGuideHowInstallCACertPage();
|
||||
await GoToGuideHowInstallCACertPageAsync();
|
||||
}
|
||||
}
|
||||
|
||||
void GoToGuideHowInstallCACertPage()
|
||||
async Task GoToGuideHowInstallCACertPageAsync()
|
||||
{
|
||||
int count = 0;
|
||||
while (XEPlatform.CurrentActivity != RequireActivity() && count < 10)
|
||||
{
|
||||
await Task.Delay(200);
|
||||
count++;
|
||||
}
|
||||
var navController = this.GetNavController();
|
||||
navController?.Navigate(Resource.Id.action_navigation_guide_export_ca_cert_to_navigation_guide_how_install_ca_cert);
|
||||
}
|
||||
|
||||
async void InstallCertificate()
|
||||
{
|
||||
var isOK = await ViewModel!.ExportCertificateFileAsync(InstallCertificateAsync);
|
||||
if (isOK)
|
||||
{
|
||||
var a = RequireActivity();
|
||||
var intent = IntermediateActivity.SetResult(new(), Result.Ok);
|
||||
a.SetResult(Result.Ok, intent);
|
||||
a.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
async Task<bool> InstallCertificateAsync(string cefFilePath)
|
||||
{
|
||||
var intent = GoToPlatformPages.GetInstallCertificateIntent(cefFilePath, IHttpProxyService.RootCertificateName);
|
||||
if (intent == null) return false;
|
||||
try
|
||||
{
|
||||
await IntermediateActivity.StartAsync(intent, NextRequestCode());
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
return IHttpProxyService.Instance.IsCurrentCertificateInstalled;
|
||||
}
|
||||
}
|
||||
|
||||
[Register(JavaPackageConstants.Fragments + nameof(GuideHowInstallCACertFragment))]
|
||||
@@ -98,29 +158,28 @@ namespace System.Application.UI.Activities
|
||||
SetOnClickListener(binding!.btnDone);
|
||||
}
|
||||
|
||||
public override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
||||
if (IHttpProxyService.Instance.IsCurrentCertificateInstalled)
|
||||
{
|
||||
var intent = IntermediateActivity.SetResult(new(), Result.Ok);
|
||||
var a = RequireActivity();
|
||||
a.SetResult(Result.Ok, intent);
|
||||
a.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnClick(View view)
|
||||
{
|
||||
if (view.Id == Resource.Id.btnDone)
|
||||
{
|
||||
GoToSystemSettingsSecurity();
|
||||
GoToPlatformPages.SystemSettingsSecurity(RequireActivity());
|
||||
return true;
|
||||
}
|
||||
return base.OnClick(view);
|
||||
}
|
||||
|
||||
async void GoToSystemSettingsSecurity()
|
||||
{
|
||||
var intent = new Intent(ASettings.ActionSecuritySettings);
|
||||
intent.AddFlags(ActivityFlags.NewTask);
|
||||
intent = await IntermediateActivity.StartAsync(intent, NextRequestCode());
|
||||
var a = RequireActivity();
|
||||
if (IHttpProxyService.Instance.IsCurrentCertificateInstalled)
|
||||
{
|
||||
intent = IntermediateActivity.SetResult(intent, Result.Ok);
|
||||
a.SetResult(Result.Ok, intent);
|
||||
}
|
||||
a.Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace System.Application.UI.Activities
|
||||
[Register(JavaPackageConstants.Activities + nameof(GuideVPNActivity))]
|
||||
[Activity(Theme = ManifestConstants.MainTheme2_NoActionBar,
|
||||
LaunchMode = LaunchMode.SingleTask,
|
||||
ConfigurationChanges = ManifestConstants.ConfigurationChanges)]
|
||||
ConfigurationChanges = ManifestConstants.ConfigurationChangesWithOutOrientationLocale)]
|
||||
internal sealed class GuideVPNActivity : BaseActivity<activity_guide_vpn>
|
||||
{
|
||||
protected override int? LayoutResource => Resource.Layout.activity_guide_vpn;
|
||||
@@ -37,6 +37,8 @@ namespace System.Application.UI.Activities
|
||||
|
||||
this.SetSupportActionBarWithNavigationClick(binding!.toolbar, true);
|
||||
|
||||
Title = string.Empty;
|
||||
|
||||
SetOnClickListener(binding.btnDone);
|
||||
}
|
||||
|
||||
@@ -51,8 +53,15 @@ namespace System.Application.UI.Activities
|
||||
SetResult(Result.Ok, intent);
|
||||
Finish();
|
||||
}
|
||||
await IntermediateActivity.StartAsync(intent,
|
||||
NextRequestCode(), onResult: OnResult);
|
||||
try
|
||||
{
|
||||
await IntermediateActivity.StartAsync(intent,
|
||||
NextRequestCode(), onResult: OnResult);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -163,7 +163,14 @@ namespace System.Application.UI.Fragments
|
||||
{
|
||||
// 需要授予 VPN 权限
|
||||
intent = new Intent(a, typeof(GuideVPNActivity));
|
||||
intent = await IntermediateActivity.StartAsync(intent, NextRequestCode());
|
||||
try
|
||||
{
|
||||
intent = await IntermediateActivity.StartAsync(intent, NextRequestCode());
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +178,14 @@ namespace System.Application.UI.Fragments
|
||||
{
|
||||
// 当未安装证书时
|
||||
intent = new Intent(a, typeof(GuideCACertActivity));
|
||||
intent = await IntermediateActivity.StartAsync(intent, NextRequestCode(), onResult: OnResult);
|
||||
try
|
||||
{
|
||||
intent = await IntermediateActivity.StartAsync(intent, NextRequestCode());
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (intent != null)
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace AndroidX.Activity.Result
|
||||
const string actualIntentExtra = "actual_intent";
|
||||
const string guidExtra = "guid";
|
||||
const string requestCodeExtra = "request_code";
|
||||
const string resultExtra = "droid_app_result";
|
||||
|
||||
static readonly ConcurrentDictionary<string?, IntermediateTask> pendingTasks =
|
||||
new();
|
||||
@@ -173,17 +174,15 @@ namespace AndroidX.Activity.Result
|
||||
public Action<Intent>? OnResult { get; }
|
||||
}
|
||||
|
||||
const string AndroidAppResult = "AndroidAppResult";
|
||||
|
||||
public static Intent SetResult(Intent? data, AndroidAppResult resultCode)
|
||||
{
|
||||
if (data == null) data = new();
|
||||
data.PutExtra(AndroidAppResult, (int)resultCode);
|
||||
data.PutExtra(resultExtra, (int)resultCode);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static AndroidAppResult GetResult(Intent data, int defaultValue = int.MinValue)
|
||||
=> (AndroidAppResult)data.GetIntExtra(AndroidAppResult, defaultValue);
|
||||
=> (AndroidAppResult)data.GetIntExtra(resultExtra, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -33,7 +33,6 @@
|
||||
android:paddingStart="@dimen/activity_horizontal_margin"
|
||||
android:paddingEnd="@dimen/activity_horizontal_margin"
|
||||
android:tint="?colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvTitle"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@@ -44,57 +43,56 @@
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:text="@string/guide_export_ca_cert_title"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc1"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ivLogo"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_export_ca_cert_desc1"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc2"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_export_ca_cert_desc2"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc3"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvDesc1"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/guide_desc_margin_bottom"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_export_ca_cert_desc3"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btnDone"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvDesc2"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@@ -105,7 +103,7 @@
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:gravity="start|center_vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:text="@string/guide_export_ca_cert_btn"
|
||||
android:text="@string/guide_export_ca_cert_btn_save"
|
||||
android:textAllCaps="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
+11
-12
@@ -33,7 +33,6 @@
|
||||
android:paddingStart="@dimen/activity_horizontal_margin"
|
||||
android:paddingEnd="@dimen/activity_horizontal_margin"
|
||||
android:tint="?colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvTitle"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@@ -44,85 +43,85 @@
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:text="@string/guide_how_install_ca_cert_title"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc1"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ivLogo"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_how_install_ca_cert_desc1"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc2"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_how_install_ca_cert_desc2"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc3"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvDesc1"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_how_install_ca_cert_desc3"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc4"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvDesc2"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_how_install_ca_cert_desc4"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvDesc5"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvDesc3"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tvDesc5"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/guide_desc_margin_bottom"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:text="@string/guide_how_install_ca_cert_desc5"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btnDone"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline_right"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline_left"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvDesc4"
|
||||
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">This certificate needs to be installed in order for Network Acceleration to work properly.</string>
|
||||
<string name="guide_export_ca_cert_desc2">The certificate is unique, generated by your device, and stored locally on the device.</string>
|
||||
<string name="guide_export_ca_cert_desc3">Please save the certificate. The next step describes how to install it manually.</string>
|
||||
<string name="guide_export_ca_cert_btn">Save it now</string>
|
||||
<string name="guide_export_ca_cert_btn_save">Save it now</string>
|
||||
<string name="guide_export_ca_cert_btn_install">Install CA certificate</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">How do I install the certificate?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. Open [Security] settings</string>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">Este certificado es necesario para que la Aceleración de Red funcione correctamente.</string>
|
||||
<string name="guide_export_ca_cert_desc2">El certificado es único, generado por su dispositivo y almacenado localmente en el mismo.</string>
|
||||
<string name="guide_export_ca_cert_desc3">Por favor, guarde el certificado. El siguiente paso describe cómo instalarlo manualmente.</string>
|
||||
<string name="guide_export_ca_cert_btn">Guárdalo ahora</string>
|
||||
<string name="guide_export_ca_cert_btn_save">Guárdalo ahora</string>
|
||||
<string name="guide_export_ca_cert_btn_install">Instalación de certificados CA</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">¿Cómo se instala un certificado?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. Abrir la configuración de [Seguridad]</string>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">Questo certificato è necessario per far funzionare correttamente Network Acceleration.</string>
|
||||
<string name="guide_export_ca_cert_desc2">Il certificato è unico, generato dal tuo dispositivo e memorizzato localmente sul dispositivo.</string>
|
||||
<string name="guide_export_ca_cert_desc3">Si prega di salvare il certificato. Il prossimo passo descrive come installarlo manualmente.</string>
|
||||
<string name="guide_export_ca_cert_btn">Salvare ora</string>
|
||||
<string name="guide_export_ca_cert_btn_save">Salvare ora</string>
|
||||
<string name="guide_export_ca_cert_btn_install">Installazione di certificati CA</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">Come si installa un certificato?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. Aprire le impostazioni [Sicurezza].</string>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">この証明書は、ネットワークアクセラレーションが正常に動作するために必要です。</string>
|
||||
<string name="guide_export_ca_cert_desc2">証明書はユニークで、デバイスによって生成され、デバイスにローカルに保存されます。</string>
|
||||
<string name="guide_export_ca_cert_desc3">証明書を保存してください。 次のステップでは、手動でインストールする方法を説明します。</string>
|
||||
<string name="guide_export_ca_cert_btn">今すぐ保存する</string>
|
||||
<string name="guide_export_ca_cert_btn_save">今すぐ保存する</string>
|
||||
<string name="guide_export_ca_cert_btn_install">CA 証明書のインストール</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">証明書をインストールするにはどうすればよいですか?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. [セキュリティ]設定を開く</string>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">네트워크가 정상적으로 작동하도록 하기 위해서 이 인증서를 설치해야 합니다.</string>
|
||||
<string name="guide_export_ca_cert_desc2">인증서는 고유하며 디바이스에서 생성되어 로컬 디바이스에 저장됩니다.</string>
|
||||
<string name="guide_export_ca_cert_desc3">인증서를 저장하십시오.다음 단계에서는 수동으로 설치하는 방법을 소개합니다.</string>
|
||||
<string name="guide_export_ca_cert_btn">지금 저장</string>
|
||||
<string name="guide_export_ca_cert_btn_save">지금 저장</string>
|
||||
<string name="guide_export_ca_cert_btn_install">CA 인증서 설치</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">인증서는 어떻게 설치합니까?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. [안전] 설정 열기</string>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">Этот сертификат необходим для правильной работы Network Acceleration.</string>
|
||||
<string name="guide_export_ca_cert_desc2">Сертификат является уникальным, генерируется вашим устройством и хранится локально на устройстве.</string>
|
||||
<string name="guide_export_ca_cert_desc3">Пожалуйста, сохраните сертификат. Следующий шаг описывает, как установить его вручную.</string>
|
||||
<string name="guide_export_ca_cert_btn">Сохранить сейчас</string>
|
||||
<string name="guide_export_ca_cert_btn_save">Сохранить сейчас</string>
|
||||
<string name="guide_export_ca_cert_btn_install">Установка сертификатов ЦС</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">Как установить сертификат?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. Откройте настройки [Безопасность]</string>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">為了使 網絡加速 正常工作,需要安裝此證書。</string>
|
||||
<string name="guide_export_ca_cert_desc2">該證書是唯一的,由您的設備生成,並存儲在本地設備上。</string>
|
||||
<string name="guide_export_ca_cert_desc3">請保存證書。 下一步介紹如何手動安裝它。</string>
|
||||
<string name="guide_export_ca_cert_btn">現在保存它</string>
|
||||
<string name="guide_export_ca_cert_btn_save">現在保存它</string>
|
||||
<string name="guide_export_ca_cert_btn_install">安装 CA 證書</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">如何安裝證書?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. 打開【安全】設置</string>
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
<string name="guide_export_ca_cert_desc1">为了使 网络加速 正常工作,需要安装此证书。</string>
|
||||
<string name="guide_export_ca_cert_desc2">该证书是唯一的,由您的设备生成,并存储在本地设备上。</string>
|
||||
<string name="guide_export_ca_cert_desc3">请保存证书。下一步介绍如何手动安装它。</string>
|
||||
<string name="guide_export_ca_cert_btn">现在保存它</string>
|
||||
<string name="guide_export_ca_cert_btn_save">现在保存它</string>
|
||||
<string name="guide_export_ca_cert_btn_install">安装 CA 证书</string>
|
||||
<!-- Guide How Install CA Cert ↓ -->
|
||||
<string name="guide_how_install_ca_cert_title">如何安装证书?</string>
|
||||
<string name="guide_how_install_ca_cert_desc1">1. 打开【安全】设置</string>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace System.Application.Services
|
||||
{
|
||||
partial interface IPlatformService
|
||||
{
|
||||
bool IsCertificateInstalled(X509Certificate2 certificate2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -807,24 +807,36 @@ namespace System.Application.Services.Implementation
|
||||
{
|
||||
if (proxyServer.CertificateManager.RootCertificate == null)
|
||||
if (GetCerFilePathGeneratedWhenNoFileExists() == null) return false;
|
||||
return IsCertificateInstalled(proxyServer.CertificateManager.RootCertificate);
|
||||
return IsCertificateInstalled(proxyServer.CertificateManager.RootCertificate, usePlatformCheck: true);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCertificateInstalled(X509Certificate2? certificate2)
|
||||
public bool IsCertificateInstalled(X509Certificate2? certificate2) => IsCertificateInstalled(certificate2, false);
|
||||
|
||||
public bool IsCertificateInstalled(X509Certificate2? certificate2, bool usePlatformCheck)
|
||||
{
|
||||
if (certificate2 == null)
|
||||
return false;
|
||||
if (certificate2.NotAfter <= DateTime.Now)
|
||||
return false;
|
||||
|
||||
if (OperatingSystem2.IsLinux)
|
||||
if (!OperatingSystem2.IsAndroid && OperatingSystem2.IsLinux)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
using var store = new X509Store(OperatingSystem2.IsMacOS ? StoreName.My : StoreName.Root, StoreLocation.CurrentUser);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
return store.Certificates.Contains(certificate2);
|
||||
|
||||
bool result;
|
||||
if (usePlatformCheck && OperatingSystem2.IsAndroid)
|
||||
{
|
||||
result = platformService.IsCertificateInstalled(certificate2);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var store = new X509Store(OperatingSystem2.IsMacOS ? StoreName.My : StoreName.Root, StoreLocation.CurrentUser);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
result = store.Certificates.Contains(certificate2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Dispose(bool disposing)
|
||||
|
||||
Reference in New Issue
Block a user