Commit 1f67e982 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

added onReceivedServerTrustAuthRequest and onReceivedClientCertRequest events...

added onReceivedServerTrustAuthRequest and onReceivedClientCertRequest events to manage SSL requests, added clearSslPreferences and clearClientCertPreferences for Android, added nodejs_server_test_auth_basic_and_ssl for testing auth and ssl requests
parent 68ff79c7
This diff is collapsed.
......@@ -13,16 +13,19 @@
- Added `onLoadResourceCustomScheme` event and `resourceCustomSchemes` option to set custom schemes that WebView must handle to load resources
- Added `onTargetBlank` event and `useOnTargetBlank` option to manage links with `target="_blank"`
- Added `ContentBlocker`, `ContentBlockerTrigger` and `ContentBlockerAction` classes and the `contentBlockers` option that allows to define a set of rules to use to block content in the WebView
- Added new WebView options: `minimumFontSize`, `debuggingEnabled`
- Added new WebView options: `minimumFontSize`, `debuggingEnabled`, `preferredContentMode`
- Added new Android WebView options: `allowContentAccess`, `allowFileAccess`, `allowFileAccessFromFileURLs`, `allowUniversalAccessFromFileURLs`, `appCacheEnabled`, `appCachePath`, `blockNetworkImage`, `blockNetworkLoads`, `cacheMode`, `cursiveFontFamily`, `defaultFixedFontSize`, `defaultFontSize`, `defaultTextEncodingName`, `disabledActionModeMenuItems`, `fantasyFontFamily`, `fixedFontFamily`, `forceDark`, `geolocationEnabled`, `layoutAlgorithm`, `loadWithOverviewMode`, `loadsImagesAutomatically`, `minimumLogicalFontSize`, `needInitialFocus`, `offscreenPreRaster`, `sansSerifFontFamily`, `serifFontFamily`, `standardFontFamily`
- Added new iOS WebView options: `applicationNameForUserAgent`, `isFraudulentWebsiteWarningEnabled`, `selectionGranularity`, `dataDetectorTypes`, `preferredContentMode`
- Added new iOS WebView options: `applicationNameForUserAgent`, `isFraudulentWebsiteWarningEnabled`, `selectionGranularity`, `dataDetectorTypes`
- Added `onGeolocationPermissionsShowPrompt` event and `GeolocationPermissionShowPromptResponse` class (available only for Android)
- Added `startSafeBrowsing`, `setSafeBrowsingWhitelist` and `getSafeBrowsingPrivacyPolicyUrl` methods (available only for Android)
- Added `clearSslPreferences` and `clearClientCertPreferences` methods (available only for Android)
- Added `onSafeBrowsingHit` event (available only for Android)
- Added `onJsAlert`, `onJsConfirm` and `onJsPrompt` events to manage javascript popup dialogs
- Added `onReceivedHttpAuthRequest` event
- Added `clearCache()` method
- Added `HttpAuthCredentialDatabase` class
- Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests
### BREAKING CHANGES
- Deleted `WebResourceRequest` class
......@@ -30,7 +33,7 @@
- Updated `ConsoleMessageLevel` class
- Updated `onLoadResource` event
- Updated `CookieManager` class
- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSChromeCustomTabsOptions`
- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSSafariOptions`
## 1.2.1
......
......@@ -93,7 +93,7 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
}
@Override
public void onMethodCall(MethodCall call, Result result) {
public void onMethodCall(MethodCall call, final Result result) {
String source;
String urlFile;
switch (call.method) {
......@@ -250,6 +250,23 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
webView.clearAllCache();
result.success(true);
break;
case "clearSslPreferences":
if (webView != null)
webView.clearSslPreferences();
result.success(true);
break;
case "clearClientCertPreferences":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.clearClientCertPreferences(new Runnable() {
@Override
public void run() {
result.success(true);
}
});
} else {
result.success(false);
}
break;
case "dispose":
dispose();
result.success(true);
......
......@@ -9,6 +9,8 @@ import android.graphics.Picture;
import android.graphics.drawable.ColorDrawable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
......@@ -479,4 +481,22 @@ public class InAppBrowserActivity extends AppCompatActivity {
if (webView != null)
webView.clearAllCache();
}
public void clearSslPreferences() {
if (webView != null)
webView.clearSslPreferences();
}
public void clearClientCertPreferences(final MethodChannel.Result result) {
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.clearClientCertPreferences(new Runnable() {
@Override
public void run() {
result.success(true);
}
});
}
else
result.success(false);
}
}
......@@ -311,6 +311,13 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
clearCache(uuid);
result.success(true);
break;
case "clearSslPreferences":
clearSslPreferences(uuid);
result.success(true);
break;
case "clearClientCertPreferences":
clearClientCertPreferences(uuid, result);
break;
default:
result.notImplemented();
}
......@@ -699,4 +706,17 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearCache();
}
public void clearSslPreferences(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearSslPreferences();
}
private void clearClientCertPreferences(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearClientCertPreferences(result);
result.success(false);
}
}
......@@ -17,7 +17,6 @@ import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList;
import android.webkit.WebHistoryItem;
import android.webkit.WebSettings;
import android.webkit.WebView;
import com.pichillilorenzo.flutter_inappbrowser.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappbrowser.ContentBlocker.ContentBlockerAction;
......@@ -41,6 +40,8 @@ import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
import static com.pichillilorenzo.flutter_inappbrowser.InAppWebView.PreferredContentModeOptionType.*;
final public class InAppWebView extends InputAwareWebView {
static final String LOG_TAG = "InAppWebView";
......@@ -221,6 +222,18 @@ final public class InAppWebView extends InputAwareWebView {
settings.setSansSerifFontFamily(options.sansSerifFontFamily);
settings.setSerifFontFamily(options.serifFontFamily);
settings.setStandardFontFamily(options.standardFontFamily);
if (options.preferredContentMode != null) {
switch (fromValue(options.preferredContentMode)) {
case DESKTOP:
setDesktopMode(true);
break;
case MOBILE:
setDesktopMode(false);
break;
case RECOMMENDED:
break;
}
}
contentBlockerHandler.getRuleList().clear();
for (Map<String, Map<String, Object>> contentBlocker : options.contentBlockers) {
......@@ -701,6 +714,24 @@ final public class InAppWebView extends InputAwareWebView {
}
}
public void setDesktopMode(final boolean enabled) {
final WebSettings webSettings = getSettings();
final String newUserAgent;
if (enabled) {
newUserAgent = webSettings.getUserAgentString().replace("Mobile", "eliboM").replace("Android", "diordnA");
}
else {
newUserAgent = webSettings.getUserAgentString().replace("eliboM", "Mobile").replace("diordnA", "Android");
}
webSettings.setUserAgentString(newUserAgent);
webSettings.setUseWideViewPort(enabled);
webSettings.setLoadWithOverviewMode(enabled);
webSettings.setSupportZoom(enabled);
webSettings.setBuiltInZoomControls(enabled);
}
@Override
public void destroy() {
super.destroy();
......
......@@ -23,11 +23,12 @@ public class InAppWebViewOptions extends Options {
public boolean javaScriptCanOpenWindowsAutomatically = false;
public boolean mediaPlaybackRequiresUserGesture = true;
public Integer textZoom = 100;
public Integer minimumFontSize = 8;
public boolean verticalScrollBarEnabled = true;
public boolean horizontalScrollBarEnabled = true;
public List<String> resourceCustomSchemes = new ArrayList<>();
public List<Map<String, Map<String, Object>>> contentBlockers = new ArrayList<>();
public Integer minimumFontSize = 8;
public Integer preferredContentMode = PreferredContentModeOptionType.RECOMMENDED.toValue();
public boolean clearSessionCache = false;
public boolean builtInZoomControls = false;
......
package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
import com.pichillilorenzo.flutter_inappbrowser.ContentBlocker.ContentBlockerActionType;
public enum PreferredContentModeOptionType {
RECOMMENDED (0),
MOBILE (1),
DESKTOP (2);
private final int value;
private PreferredContentModeOptionType(int value) {
this.value = value;
}
public boolean equalsValue(int otherValue) {
return value == otherValue;
}
public static PreferredContentModeOptionType fromValue(int value) {
for( PreferredContentModeOptionType type : PreferredContentModeOptionType.values()) {
if(value == type.toValue())
return type;
}
throw new IllegalArgumentException("No enum constant: " + value);
}
public int toValue() {
return this.value;
}
}
......@@ -5,8 +5,16 @@ import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
......@@ -23,12 +31,11 @@ public class Util {
public static String getUrlAsset(PluginRegistry.Registrar registrar, String assetFilePath) throws IOException {
String key = registrar.lookupKeyForAsset(assetFilePath);
AssetManager mg = registrar.activeContext().getResources().getAssets();
InputStream is = null;
IOException e = null;
try {
is = mg.open(key);
is = getFileAsset(registrar, assetFilePath);
} catch (IOException ex) {
e = ex;
} finally {
......@@ -47,51 +54,98 @@ public class Util {
return ANDROID_ASSET_URL + key;
}
public static WaitFlutterResult invokeMethodAndWait(final MethodChannel channel, final String method, final Object arguments) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
final Map<String, Object> flutterResultMap = new HashMap<>();
flutterResultMap.put("result", null);
flutterResultMap.put("error", null);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
channel.invokeMethod(method, arguments, new MethodChannel.Result() {
@Override
public void success(Object result) {
flutterResultMap.put("result", result);
latch.countDown();
}
@Override
public void error(String s, String s1, Object o) {
flutterResultMap.put("error", "ERROR: " + s + " " + s1);
flutterResultMap.put("result", o);
latch.countDown();
}
@Override
public void notImplemented() {
latch.countDown();
}
});
}
});
public static InputStream getFileAsset(PluginRegistry.Registrar registrar, String assetFilePath) throws IOException {
String key = registrar.lookupKeyForAsset(assetFilePath);
AssetManager mg = registrar.activeContext().getResources().getAssets();
return mg.open(key);
}
latch.await();
public static WaitFlutterResult invokeMethodAndWait(final MethodChannel channel, final String method, final Object arguments) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
final Map<String, Object> flutterResultMap = new HashMap<>();
flutterResultMap.put("result", null);
flutterResultMap.put("error", null);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
channel.invokeMethod(method, arguments, new MethodChannel.Result() {
@Override
public void success(Object result) {
flutterResultMap.put("result", result);
latch.countDown();
}
@Override
public void error(String s, String s1, Object o) {
flutterResultMap.put("error", "ERROR: " + s + " " + s1);
flutterResultMap.put("result", o);
latch.countDown();
}
@Override
public void notImplemented() {
latch.countDown();
}
});
}
});
latch.await();
return new WaitFlutterResult(flutterResultMap.get("result"), (String) flutterResultMap.get("error"));
}
public static class WaitFlutterResult {
public Object result;
public String error;
return new WaitFlutterResult(flutterResultMap.get("result"), (String) flutterResultMap.get("error"));
public WaitFlutterResult(Object r, String e) {
result = r;
error = e;
}
}
public static class WaitFlutterResult {
public Object result;
public String error;
public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate(PluginRegistry.Registrar registrar, String certificatePath, String certificatePassword, String keyStoreType) {
public WaitFlutterResult(Object r, String e) {
result = r;
error = e;
PrivateKeyAndCertificates privateKeyAndCertificates = null;
try {
InputStream certificateFileStream = getFileAsset(registrar, certificatePath);
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(certificateFileStream, certificatePassword != null ? certificatePassword.toCharArray() : null);
Enumeration<String> aliases = keyStore.aliases();
String alias = aliases.nextElement();
Key key = keyStore.getKey(alias, certificatePassword.toCharArray());
if (key instanceof PrivateKey) {
PrivateKey privateKey = (PrivateKey)key;
Certificate cert = keyStore.getCertificate(alias);
X509Certificate[] certificates = new X509Certificate[1];
certificates[0] = (X509Certificate)cert;
privateKeyAndCertificates = new PrivateKeyAndCertificates(privateKey, certificates);
}
certificateFileStream.close();
} catch (Exception e) {
e.printStackTrace();
Log.e(LOG_TAG, e.getMessage());
}
return privateKeyAndCertificates;
}
public static class PrivateKeyAndCertificates {
public X509Certificate[] certificates;
public PrivateKey privateKey;
public PrivateKeyAndCertificates(PrivateKey privateKey, X509Certificate[] certificates) {
this.privateKey = privateKey;
this.certificates = certificates;
}
}
}
......@@ -82,11 +82,11 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
//initialUrl: "https://www.youtube.com/embed/M7lc1UVf-VE?playsinline=1",
//initialUrl: "https://flutter.dev/",
initialUrl: "https://flutter.dev/",
//initialUrl: "chrome://safe-browsing/match?type=malware",
//initialUrl: "http://192.168.1.20:8081/",
//initialUrl: "https://192.168.1.20:4433/authenticate",
initialFile: "assets/index.html",
//initialUrl: "https://192.168.1.20:4433/",
//initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: [
InAppWebViewOptions(
......@@ -95,15 +95,16 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
useOnTargetBlank: true,
//useOnLoadResource: true,
useOnDownloadStart: true,
preferredContentMode: InAppWebViewUserPreferredContentMode.DESKTOP,
resourceCustomSchemes: ["my-special-custom-scheme"],
contentBlockers: [
/*contentBlockers: [
ContentBlocker(
ContentBlockerTrigger(".*",
resourceType: [ContentBlockerTriggerResourceType.IMAGE, ContentBlockerTriggerResourceType.STYLE_SHEET],
ifTopUrl: ["https://getbootstrap.com/"]),
ContentBlockerAction(ContentBlockerActionType.BLOCK)
)
]
]*/
),
AndroidInAppWebViewOptions(
databaseEnabled: true,
......@@ -113,9 +114,6 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
safeBrowsingEnabled: true,
//blockNetworkImage: true,
),
iOSInAppWebViewOptions(
preferredContentMode: iOSInAppWebViewUserPreferredContentMode.DESKTOP
)
],
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
......@@ -140,6 +138,13 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
},
onLoadStop: (InAppWebViewController controller, String url) async {
print("stopped $url");
if (Platform.isAndroid) {
controller.clearSslPreferences();
controller.clearClientCertPreferences();
}
// controller.injectScriptCode("""
// document.getElementById("SEARCH_WORD" + 5).scrollIntoView();
// """);
},
onLoadError: (InAppWebViewController controller, String url, int code, String message) async {
print("error $url: $code, $message");
......@@ -241,11 +246,20 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
return new SafeBrowsingResponse(report: true, action: action);
},
onReceivedHttpAuthRequest: (InAppWebViewController controller, HttpAuthChallenge challenge) async {
print("HTTP AUTH REQUEST: " + challenge.protectionSpace.host + ", realm: " + challenge.protectionSpace.realm +
", previous failure count: " + challenge.previousFailureCount.toString());
print("HTTP AUTH REQUEST: ${challenge.protectionSpace.host}, realm: ${challenge.protectionSpace.realm}, previous failure count: ${challenge.previousFailureCount.toString()}");
return new HttpAuthResponse(username: "USERNAME", password: "PASSWORD", action: HttpAuthResponseAction.USE_SAVED_HTTP_AUTH_CREDENTIALS, permanentPersistence: true);
},
onReceivedServerTrustAuthRequest: (InAppWebViewController controller, ServerTrustChallenge challenge) async {
print("SERVER TRUST AUTH REQUEST: ${challenge.protectionSpace.host}, SSL ERROR CODE: ${challenge.error.toString()}, MESSAGE: ${challenge.message}");
return new ServerTrustAuthResponse(action: ServerTrustAuthResponseAction.PROCEED);
},
onReceivedClientCertRequest: (InAppWebViewController controller, ClientCertChallenge challenge) async {
print("CLIENT CERT REQUEST: ${challenge.protectionSpace.host}");
return new ClientCertResponse(certificatePath: "assets/certificate.pfx", certificatePassword: "", androidKeyStoreType: "PKCS12", action: ClientCertResponseAction.PROCEED);
},
),
),
),
......
......@@ -42,6 +42,7 @@ flutter:
uses-material-design: true
assets:
- assets/certificate.pfx
- assets/index.html
- assets/page-1.html
- assets/page-2.html
......
......@@ -38,22 +38,25 @@ class CredentialDatabase: NSObject, FlutterPlugin {
"realm": protectionSpace.realm,
"port": protectionSpace.port
] as [String : Any?]
var crendentials: [[String: String?]] = []
for c in credentials {
let credential: [String: String?] = [
"username": c.value.user,
"password": c.value.password,
]
crendentials.append(credential)
if let username = c.value.user, let password = c.value.password {
let credential: [String: String] = [
"username": username,
"password": password,
]
crendentials.append(credential)
}
}
let dict = [
"protectionSpace": protectionSpaceDict,
"credentials": crendentials
] as [String : Any]
allCredentials.append(dict)
}
if crendentials.count > 0 {
let dict = [
"protectionSpace": protectionSpaceDict,
"credentials": crendentials
] as [String : Any]
allCredentials.append(dict)
} }
result(allCredentials)
break
case "getHttpAuthCredentials":
......@@ -70,11 +73,13 @@ class CredentialDatabase: NSObject, FlutterPlugin {
if protectionSpace.host == host && protectionSpace.realm == realm &&
protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort {
for c in credentials {
let credential: [String: String?] = [
"username": c.value.user,
"password": c.value.password,
]
crendentials.append(credential)
if let username = c.value.user, let password = c.value.password {
let credential: [String: String] = [
"username": username,
"password": password,
]
crendentials.append(credential)
}
}
break
}
......@@ -148,8 +153,11 @@ class CredentialDatabase: NSObject, FlutterPlugin {
protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort {
protectionSpaceCredential = protectionSpace
for c in credentials {
credentialsToRemove.append(c.value)
if let _ = c.value.user, let _ = c.value.password {
credentialsToRemove.append(c.value)
}
}
break
}
}
......
This diff is collapsed.
......@@ -21,4 +21,3 @@ A new Flutter plugin.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.swift_version = '5.0'
end
......@@ -410,7 +410,17 @@ class InAppBrowser {
///Event fires when a WebView received an HTTP authentication request. The default behavior is to cancel the request.
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the auth challenge.
Future<HttpAuthResponse> onReceivedHttpAuthRequest(String url, HttpAuthChallenge challenge) {
Future<HttpAuthResponse> onReceivedHttpAuthRequest(HttpAuthChallenge challenge) {
}
///
Future<ServerTrustAuthResponse> onReceivedServerTrustAuthRequest(ServerTrustChallenge challenge) {
}
///
Future<ClientCertResponse> onReceivedClientCertRequest(ClientCertChallenge challenge) {
}
......
......@@ -10,14 +10,13 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
import 'http_auth_credentials_database.dart';
import 'types.dart';
import 'in_app_browser.dart';
import 'channel_manager.dart';
import 'webview_options.dart';
/*
* TODO: injectFileFromAssets, injectJavaScriptBeforeLoad
* TODO: injectJavaScriptBeforeLoad
*/
///Initial [data] as a content for an [InAppWebView] instance, using [baseUrl] as the base URL for it.
......@@ -182,6 +181,12 @@ class InAppWebView extends StatefulWidget {
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the auth challenge.
final onReceivedHttpAuthRequestCallback onReceivedHttpAuthRequest;
///
final onReceivedServerTrustAuthRequestCallback onReceivedServerTrustAuthRequest;
///
final onReceivedClientCertRequestCallback onReceivedClientCertRequest;
///Initial url that will be loaded.
final String initialUrl;
///Initial asset file that will be loaded. See [InAppWebView.loadFile()] for explanation.
......@@ -226,6 +231,8 @@ class InAppWebView extends StatefulWidget {
this.onJsPrompt,
this.onSafeBrowsingHit,
this.onReceivedHttpAuthRequest,
this.onReceivedServerTrustAuthRequest,
this.onReceivedClientCertRequest,
this.gestureRecognizers,
}) : super(key: key);
......@@ -487,7 +494,34 @@ class InAppWebViewController {
if (_widget != null && _widget.onReceivedHttpAuthRequest != null)
return (await _widget.onReceivedHttpAuthRequest(this, challenge))?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedHttpAuthRequest(host, challenge))?.toMap();
return (await _inAppBrowser.onReceivedHttpAuthRequest(challenge))?.toMap();
break;
case "onReceivedServerTrustAuthRequest":
String host = call.arguments["host"];
String protocol = call.arguments["protocol"];
String realm = call.arguments["realm"];
int port = call.arguments["port"];
int error = call.arguments["error"];
String message = call.arguments["message"];
Uint8List serverCertificate = call.arguments["serverCertificate"];
var protectionSpace = ProtectionSpace(host: host, protocol: protocol, realm: realm, port: port);
var challenge = ServerTrustChallenge(protectionSpace: protectionSpace, error: error, message: message, serverCertificate: serverCertificate);
if (_widget != null && _widget.onReceivedServerTrustAuthRequest != null)
return (await _widget.onReceivedServerTrustAuthRequest(this, challenge))?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedServerTrustAuthRequest(challenge))?.toMap();
break;
case "onReceivedClientCertRequest":
String host = call.arguments["host"];
String protocol = call.arguments["protocol"];
String realm = call.arguments["realm"];
int port = call.arguments["port"];
var protectionSpace = ProtectionSpace(host: host, protocol: protocol, realm: realm, port: port);
var challenge = ClientCertChallenge(protectionSpace: protectionSpace);
if (_widget != null && _widget.onReceivedClientCertRequest != null)
return (await _widget.onReceivedClientCertRequest(this, challenge))?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedClientCertRequest(challenge))?.toMap();
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
......@@ -847,7 +881,7 @@ class InAppWebViewController {
}
///Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it.
///__safeBrowsingEnabled__
///
///**NOTE for iOS**: available from iOS 11.0+.
Future<Uint8List> takeScreenshot() async {
Map<String, dynamic> args = <String, dynamic>{};
......@@ -965,7 +999,7 @@ class InAppWebViewController {
return await _channel.invokeMethod('getSafeBrowsingPrivacyPolicyUrl', args);
}
///Clear all the webview's cache
///Clears all the webview's cache
Future<void> clearCache() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
......@@ -975,9 +1009,36 @@ class InAppWebViewController {
await _channel.invokeMethod('clearCache', args);
}
///Clears the SSL preferences table stored in response to proceeding with SSL certificate errors.
///
///**NOTE**: available only for Android.
Future<void> clearSslPreferences() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('clearSslPreferences', args);
}
///Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests.
///Note that WebView automatically clears these preferences when the system keychain is updated.
///The preferences are shared by all the WebViews that are created by the embedder application.
///
///**NOTE**: On iOS certificate-based credentials are never stored permanently.
///
///**NOTE**: available only for Android.
Future<void> clearClientCertPreferences() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('clearClientCertPreferences', args);
}
///Dispose/Destroy the WebView.
Future<void> _dispose() async {
await _channel.invokeMethod('dispose');
}
}
import 'dart:typed_data';
import 'package:uuid/uuid.dart';
import 'package:flutter/services.dart';
import 'package:flutter/cupertino.dart';
......@@ -336,6 +338,79 @@ class HttpAuthCredential {
HttpAuthCredential({@required this.username, @required this.password}): assert(username != null && password != null);
}
///
class ServerTrustAuthResponseAction {
final int _value;
const ServerTrustAuthResponseAction._internal(this._value);
toValue() => _value;
static const CANCEL = const ServerTrustAuthResponseAction._internal(0);
static const PROCEED = const ServerTrustAuthResponseAction._internal(1);
}
///
class ServerTrustAuthResponse {
ServerTrustAuthResponseAction action;
ServerTrustAuthResponse({this.action = ServerTrustAuthResponseAction.CANCEL});
Map<String, dynamic> toMap() {
return {
"action": action?.toValue()
};
}
}
///
class ServerTrustChallenge {
ProtectionSpace protectionSpace;
int error;
String message;
Uint8List serverCertificate;
ServerTrustChallenge({@required this.protectionSpace, @required this.error, this.message, this.serverCertificate}): assert(protectionSpace != null && error != null);
}
///
class ClientCertResponseAction {
final int _value;
const ClientCertResponseAction._internal(this._value);
toValue() => _value;
static const CANCEL = const ClientCertResponseAction._internal(0);
static const PROCEED = const ClientCertResponseAction._internal(1);
static const IGNORE = const ClientCertResponseAction._internal(2);
}
///
class ClientCertResponse {
String certificatePath;
String certificatePassword;
String androidKeyStoreType;
ClientCertResponseAction action;
ClientCertResponse({this.certificatePath, this.certificatePassword = "", this.androidKeyStoreType = "PKCS12", this.action = ClientCertResponseAction.CANCEL}) {
if (this.action == ClientCertResponseAction.PROCEED)
assert(certificatePath != null && certificatePath.isNotEmpty);
}
Map<String, dynamic> toMap() {
return {
"certificatePath": certificatePath,
"certificatePassword": certificatePassword,
"androidKeyStoreType": androidKeyStoreType,
"action": action?.toValue()
};
}
}
///
class ClientCertChallenge {
ProtectionSpace protectionSpace;
ClientCertChallenge({@required this.protectionSpace}): assert(protectionSpace != null);
}
///
class AndroidInAppWebViewCacheMode {
final int _value;
......@@ -421,14 +496,14 @@ class iOSInAppWebViewDataDetectorTypes {
}
///
class iOSInAppWebViewUserPreferredContentMode {
class InAppWebViewUserPreferredContentMode {
final int _value;
const iOSInAppWebViewUserPreferredContentMode._internal(this._value);
const InAppWebViewUserPreferredContentMode._internal(this._value);
toValue() => _value;
static const RECOMMENDED = const iOSInAppWebViewUserPreferredContentMode._internal(0);
static const MOBILE = const iOSInAppWebViewUserPreferredContentMode._internal(1);
static const DESKTOP = const iOSInAppWebViewUserPreferredContentMode._internal(2);
static const RECOMMENDED = const InAppWebViewUserPreferredContentMode._internal(0);
static const MOBILE = const InAppWebViewUserPreferredContentMode._internal(1);
static const DESKTOP = const InAppWebViewUserPreferredContentMode._internal(2);
}
///
......@@ -489,4 +564,6 @@ typedef onJsAlertCallback = Future<JsAlertResponse> Function(InAppWebViewControl
typedef onJsConfirmCallback = Future<JsConfirmResponse> Function(InAppWebViewController controller, String message);
typedef onJsPromptCallback = Future<JsPromptResponse> Function(InAppWebViewController controller, String message, String defaultValue);
typedef onSafeBrowsingHitCallback = Future<SafeBrowsingResponse> Function(InAppWebViewController controller, String url, SafeBrowsingThreat threatType);
typedef onReceivedHttpAuthRequestCallback = Future<HttpAuthResponse> Function(InAppWebViewController controller, HttpAuthChallenge challenge);
\ No newline at end of file
typedef onReceivedHttpAuthRequestCallback = Future<HttpAuthResponse> Function(InAppWebViewController controller, HttpAuthChallenge challenge);
typedef onReceivedServerTrustAuthRequestCallback = Future<ServerTrustAuthResponse> Function(InAppWebViewController controller, ServerTrustChallenge challenge);
typedef onReceivedClientCertRequestCallback = Future<ClientCertResponse> Function(InAppWebViewController controller, ClientCertChallenge challenge);
......@@ -35,11 +35,12 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
bool horizontalScrollBarEnabled;
List<String> resourceCustomSchemes;
List<ContentBlocker> contentBlockers;
InAppWebViewUserPreferredContentMode preferredContentMode;
InAppWebViewOptions({this.useShouldOverrideUrlLoading = false, this.useOnLoadResource = false, this.useOnDownloadStart = false, this.useOnTargetBlank = false,
this.clearCache = false, this.userAgent = "", this.javaScriptEnabled = true, this.debuggingEnabled = false, this.javaScriptCanOpenWindowsAutomatically = false,
this.mediaPlaybackRequiresUserGesture = true, this.textZoom = 100, this.minimumFontSize, this.verticalScrollBarEnabled = true, this.horizontalScrollBarEnabled = true,
this.resourceCustomSchemes = const [], this.contentBlockers = const []}) {
this.resourceCustomSchemes = const [], this.contentBlockers = const [], this.preferredContentMode = InAppWebViewUserPreferredContentMode.RECOMMENDED}) {
if (this.minimumFontSize == null)
this.minimumFontSize = Platform.isAndroid ? 8 : 0;
}
......@@ -66,6 +67,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
"horizontalScrollBarEnabled": horizontalScrollBarEnabled,
"resourceCustomSchemes": resourceCustomSchemes,
"contentBlockers": contentBlockersMapList,
"preferredContentMode": preferredContentMode?.toValue()
};
}
}
......@@ -179,13 +181,11 @@ class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptio
bool isFraudulentWebsiteWarningEnabled;
iOSInAppWebViewSelectionGranularity selectionGranularity;
List<iOSInAppWebViewDataDetectorTypes> dataDetectorTypes;
iOSInAppWebViewUserPreferredContentMode preferredContentMode;
iOSInAppWebViewOptions({this.disallowOverScroll = false, this.enableViewportScale = false, this.suppressesIncrementalRendering = false, this.allowsAirPlayForMediaPlayback = true,
this.allowsBackForwardNavigationGestures = true, this.allowsLinkPreview = true, this.ignoresViewportScaleLimits = false, this.allowsInlineMediaPlayback = false,
this.allowsPictureInPictureMediaPlayback = true, this.transparentBackground = false, this.applicationNameForUserAgent = "", this.isFraudulentWebsiteWarningEnabled = true,
this.selectionGranularity = iOSInAppWebViewSelectionGranularity.DYNAMIC, this.dataDetectorTypes = const [iOSInAppWebViewDataDetectorTypes.NONE],
this.preferredContentMode = iOSInAppWebViewUserPreferredContentMode.RECOMMENDED
this.selectionGranularity = iOSInAppWebViewSelectionGranularity.DYNAMIC, this.dataDetectorTypes = const [iOSInAppWebViewDataDetectorTypes.NONE]
});
@override
......@@ -209,8 +209,7 @@ class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptio
"applicationNameForUserAgent": applicationNameForUserAgent,
"isFraudulentWebsiteWarningEnabled": isFraudulentWebsiteWarningEnabled,
"selectionGranularity": selectionGranularity.toValue(),
"dataDetectorTypes": dataDetectorTypesList,
"preferredContentMode": preferredContentMode.toValue(),
"dataDetectorTypes": dataDetectorTypesList
};
}
}
......
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.history/
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIFgDCCA2gCCQD+lncxaKtzfDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMC
VVMxCzAJBgNVBAgMAk1BMQ8wDQYDVQQHDAZCb3N0b24xEzARBgNVBAoMCkV4YW1w
bGUgQ28xEDAOBgNVBAsMB3RlY2hvcHMxCzAJBgNVBAMMAmNhMSAwHgYJKoZIhvcN
AQkBFhFjZXJ0c0BleGFtcGxlLmNvbTAeFw0xOTEwMzAyMzMzMTVaFw00NzAzMTYy
MzMzMTVaMIGBMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJv
c3RvbjETMBEGA1UECgwKRXhhbXBsZSBDbzEQMA4GA1UECwwHdGVjaG9wczELMAkG
A1UEAwwCY2ExIDAeBgkqhkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0K1Bul8vSlC90KFus9gW3V3b+6qz
Ji0fw5R1S0jeAPMA6IK+b+hBhdCpRKcq0PIZggwcBbk3zYKxAn5rLlSGj5eSQGZz
kpGUo0rwnFZF0L7bID0bmw0ELCHt3Z/cP5rx3UvM5a2V65j+ieiP8Fn5X5IKW+vz
Rehi1G0imTYjXM8so/Te8HkUjfWhvPofd2mss6fLlMViUIL0xJf6BML6Ds4nL5+8
M3zpolhPMXWSaFbQSssF6VuUFi8shIdEUNg3UAbTwUV6DVqYcYBWyrKjm1VM2Bk6
f5zPZVuwX52lP9ko1pgIFuZA18ErGv8Y5tPQQuzXVXxTpi7ToTZwa/W32tuyfvyo
bShw4ejRlrxj62nQTQcCYMDXjn/Kt/JPSlY6Lnd0x1iky5kJb0cSiWv/RPDlS5FF
0NSIpz6ZPS0mP7o6eAMwDW+6TqCZvzH+gT3ilFkZLMrIeNTjmi/lu46JigB6Brtg
nIZzI5DpGMxp2WkCA+BwYz9M8MykST+rCQ4Ikw8OhxBlxQtuEk6JEkozbztvhuqv
MJJeMf/rz1Y9bWl40dSDtvISo7FACVhlMSBqgkBkrYuJL8n0hCLqO65EkQrlMEKw
ON4XQ8eXLjv0XclLw7frCGGWxprc+nUZ8aiXki7pz3m3CC09GLVTHL2NnBdzMVkz
C/NdgQW16Hnn1xcCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAr0vvKqfBz3+GbFvm
IcMwNW+qVADXucP5Z0L9w93rIWU3957cXce/6mqYlUGPu9Rq+TMLn8tLX05Vhr9A
bp6QCCGhK+hRJ+BGmebTBFGj198VgQj9Nsvg8T1Px10oandzGD8dnGSgAB5GNTuV
c0pq4B1aW+NA9N5h/bGyrn0luYaXdsbV2jyr++waSAKcWtetwfrj5CErnQIAxUPo
LrEg75HMmdXZsCYhpPgeyHmPtmJN/czEVIQbQk/cjWzaEh7dKEpa9inBHf7DMBnS
M5xqnABVhgxCmC6wJ8OTfzY5OR2zHg2Xdra4YNQo88vmyzdvMpD+p1rxxI2ZDpds
9Eke2VtuZqi4wcEakHlSjTFMs8fF/x46+oGBNoWTcPzlDXyUiRMIGZO6zzNrc0Ez
sqgazhDQUH3Lg0dDHqPvSLw/zkyXPjh89fksspv00RP7yHUpyKl1Q+pCxQfflTes
KOkoj5OUzOWCbm6AvumVfQk302HbSqVjz9AQfoPVk8UfXoJ0FCF5LaynmBLJz+6l
2E5Up3gdDDh6qpNS5TLH6b2sKErQweEBfRAdo1fpp2RUEUOqV8uivFXVpQSc+TUV
RU1khy+tTiCnnjCKr+Xlkv/bvHZTv9hSx1TK3xsZkjHr5zzj7mltzmvQdpHVwUbD
lrzYwz1UU//M2zwtN5nHjE+bnks=
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
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
TDsQ2Rq7lfN7Gx+ugLnDlrnk1Q==
-----END ENCRYPTED PRIVATE KEY-----
[ ca ]
default_ca = CA_default
[ CA_default ]
serial = ca-serial
crl = ca-crl.pem
database = ca-database.txt
name_opt = CA_default
cert_opt = CA_default
default_crl_days = 9999
default_md = md5
[ req ]
default_bits = 4096
days = 9999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
output_password = password
[ req_distinguished_name ]
C = US
ST = MA
L = Boston
O = Example Co
OU = techops
CN = ca
emailAddress = certs@example.com
[ req_attributes ]
challengePassword = test
-----BEGIN CERTIFICATE-----
MIIFijCCA3KgAwIBAgIJALg+W/pyOZ5qMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD
VQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjETMBEGA1UECgwK
RXhhbXBsZSBDbzEQMA4GA1UECwwHdGVjaG9wczELMAkGA1UEAwwCY2ExIDAeBgkq
hkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMB4XDTE5MTAzMDIzMzcwOVoXDTIy
MDcyNTIzMzcwOVowgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
BwwGQm9zdG9uMRMwEQYDVQQKDApFeGFtcGxlIENvMRAwDgYDVQQLDAd0ZWNob3Bz
MRAwDgYDVQQDDAdjbGllbnQxMSAwHgYJKoZIhvcNAQkBFhFjZXJ0c0BleGFtcGxl
LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPWhU8of86y3Lols
0cU40+cbCcAhOEsdDiouVKX9cpnYoP5IIsTOiQHjAcMYekTMNXxLcGGa8FWO1bDW
6WjvzNi0s2xqYMThP5h7m5XK4PR6NjLnE8I0kyfYjvx4vN/AXNWJXgNDJ+dkm3O0
ceXzMzswuLqrhEv7UpkJm37znimOBtP7JSFmoz5mT+/s3Aojzop1Le1VSPVANIbu
PgdsIdoNMR8oJrKai0PourJKuvOV5qiNm0123+lq9x4R+zoY2AIB34o9RJfcuUZs
+IqDt+SyL3MHwuP8OMmYyU6yerfWLZ2Ywsg01uDGQMaHfPH1S8d8Hiq4Vwfi9RWE
kvifb4eQDBzVN3x1Hn/1cEghaLneDiRRwRiFZFs/WKvafxMOY4M30gpuSStHzIt/
wE+N8vC8KNW2TyyPAkCq6L8BjOlJ7EX0eilbSroMz/SeTO8+t4+N9vJ5/4e4dSSQ
zo3Sdw3K8sdK7zoBToWGW26yCSEvnSBjNyWvNKLWsHM1wKxbN85sDYdeyn7pvjHe
K1g0eQF/WGbEyHCTws3tDCo/wfpbZNtkW1w8zlBAmpbZdNZDs4769pZ/tb9wctUk
TasbXlXedMmmw2eOZ3d/hj0REFpbl/34ClQSTnlVQJKv/7CwqzJWDUd5uWzaHPtr
hzUOJDKoDBEvfL+yAEJNMM8maGcpAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGhm
496UQQKPqXUXl52lPUhchjCxecfukVrLf2GR3H8r9W6s46pu60MGZBip7TQowXGN
v4uZKABxOkI7VoRUhndsO8KiR39DlmE/SocSrEyfe6cblMaMr7c6oTojcYiXHLbi
Wy52O5TX1iqMBNyrvPAfDjOubkaUF0iuyh1Vzn5OuHvWfmC5uOONHIUCukeyg+hg
wxYH5vYduhYiqmdAPNHrqrGRqOfbwG6KTMaqH6xihupJsgcxwVpzbdWWxPU37tZE
sI1RVS26Z6XuA2j1uQ4BzRUbGlXqvESYV9jSkKYvNfMqVDL+g2h9xumlPtTIiP6b
GZIN4zel7WhaOdftnz5w4AdaPt3sYXxTda95973TNe072tgR/lJsvobW1szSo0k8
m2AbWeepzeKftYanCydRz5MnlOX8mf3HaL0QqreQwxaiF40mOUVcMPJfY2pK25qU
pVK9E3oA1ufc7+8Hnx4KsE9DO/1VyCrpBq0LwUKjmhYTLChsuH0Gpj+/pqioWNKB
c6Mt+APzGG8jqWrwMlsixK2U6G22zASpFBWuFhQIShkL819zgpRB67XPQUgKkbQT
4wF9cR4xwHvz8NsFHyXGFkI3U9yGGOVXWMOQ+ZhLyWGkwg096mVro/AtGveAs0sr
QWfJbuZM/gWlaojLGqtatDEc+tfRZ7g+nxU+PhQq
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIE5TCCAs0CAQAwgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
BwwGQm9zdG9uMRMwEQYDVQQKDApFeGFtcGxlIENvMRAwDgYDVQQLDAd0ZWNob3Bz
MRAwDgYDVQQDDAdjbGllbnQxMSAwHgYJKoZIhvcNAQkBFhFjZXJ0c0BleGFtcGxl
LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPWhU8of86y3Lols
0cU40+cbCcAhOEsdDiouVKX9cpnYoP5IIsTOiQHjAcMYekTMNXxLcGGa8FWO1bDW
6WjvzNi0s2xqYMThP5h7m5XK4PR6NjLnE8I0kyfYjvx4vN/AXNWJXgNDJ+dkm3O0
ceXzMzswuLqrhEv7UpkJm37znimOBtP7JSFmoz5mT+/s3Aojzop1Le1VSPVANIbu
PgdsIdoNMR8oJrKai0PourJKuvOV5qiNm0123+lq9x4R+zoY2AIB34o9RJfcuUZs
+IqDt+SyL3MHwuP8OMmYyU6yerfWLZ2Ywsg01uDGQMaHfPH1S8d8Hiq4Vwfi9RWE
kvifb4eQDBzVN3x1Hn/1cEghaLneDiRRwRiFZFs/WKvafxMOY4M30gpuSStHzIt/
wE+N8vC8KNW2TyyPAkCq6L8BjOlJ7EX0eilbSroMz/SeTO8+t4+N9vJ5/4e4dSSQ
zo3Sdw3K8sdK7zoBToWGW26yCSEvnSBjNyWvNKLWsHM1wKxbN85sDYdeyn7pvjHe
K1g0eQF/WGbEyHCTws3tDCo/wfpbZNtkW1w8zlBAmpbZdNZDs4769pZ/tb9wctUk
TasbXlXedMmmw2eOZ3d/hj0REFpbl/34ClQSTnlVQJKv/7CwqzJWDUd5uWzaHPtr
hzUOJDKoDBEvfL+yAEJNMM8maGcpAgMBAAGgGTAXBgkqhkiG9w0BCQcxCgwIcGFz
c3dvcmQwDQYJKoZIhvcNAQELBQADggIBAJal3mvhA+zM72cXUY1IYIVVS9QuSzqC
GkUT8O174bD1acc7KEm0uGS628sR0mFCKArfH9YTjUOX1+jORPBhVCXeg9xp/PPg
9mjTHyKPJu2vnq6GaS1WXqEOQJkppV5fBqciIDRQOu1goR2I21qjEUnVnb82jRXv
DpZ9YkgyMdf2Li9taj2snJSfXBwjhNH78lXmRz/HYTQSHyih4dfpdLpeIK8g+0uR
8bkJzga5hc2dDEyQQ+xQ+jVBdiAT6R/zV/V7ghJDHeJ4HuLuIVh9zIbAz0jPvG7u
pumHW3Lbr5ISwxmhOp1RczxWeRktP+8aVP0Uk5D/5EGxs8F+lbU4lh0RTm0ae6W1
UMExBn056C46ypvp7H0vLiijyhyVjo8kfz8HA392TlCOYxaJB2EaUoJA3yu5lb8w
nSQrlGCtA8ba9ceMFhjzIxE6I7qf93GZlK9m7HcqEdFNkm/byo2gQ5/SMSpOiL4C
IuK9p/bTBwpJL88ibAOq/V8IZBPRcyWnJcL7KzQKQGOVpl2egrf4Iqn5/FZwXpmL
zIVDHSRP1NwTqkAX1JxoHn7bjDDkhtB6V4qy2/uqscTBPA2m/Z+rJofusjsHblrN
nrQnzcwsiVU/gPgNUPTZi2wmxAkc7zFvnR3F1NCjLEr3G5rmF+M9aT3/5w0U3zOW
JN5HS6NqtcFI
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
[ req ]
default_bits = 4096
days = 9999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
x509_extensions = v3_ca
[ req_distinguished_name ]
C = US
ST = MA
L = Boston
O = Example Co
OU = techops
CN = client1
emailAddress = certs@example.com
[ req_attributes ]
challengePassword = password
[ v3_ca ]
authorityInfoAccess = @issuer_info
[ issuer_info ]
OCSP;URI.0 = http://ocsp.example.com/
caIssuers;URI.0 = http://example.com/ca.cert
-----BEGIN CERTIFICATE-----
MIIFijCCA3KgAwIBAgIJALg+W/pyOZ5rMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD
VQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjETMBEGA1UECgwK
RXhhbXBsZSBDbzEQMA4GA1UECwwHdGVjaG9wczELMAkGA1UEAwwCY2ExIDAeBgkq
hkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMB4XDTE5MTAzMDIzMzcxNFoXDTIy
MDcyNTIzMzcxNFowgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
BwwGQm9zdG9uMRMwEQYDVQQKDApFeGFtcGxlIENvMRAwDgYDVQQLDAd0ZWNob3Bz
MRAwDgYDVQQDDAdjbGllbnQyMSAwHgYJKoZIhvcNAQkBFhFjZXJ0c0BleGFtcGxl
LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO2ARFzN+hQgmnEj
OXHcOVjCPH6g/UNXwUNjtEUBg+EDTGliOC8If6ObFjW4tfIjwgGdhKt++92LRxDe
BauM8al7QK8yZhw7I7waqm0C4tIw4MdAlcRxZ0gEG7l5i9jU55yPpUcxZ1VE0VuH
ADgAosZtjltsBv03tq2Cf11jTEcaly4ze/8vDaAyl+M4u9FrflPnYoPmCiMBTz1j
1mdVtGsg2nGk+MA5RX9bMwWZq5bT9j2RG7PDMoc139SieQx4/5aVqIH628K7X0xE
/YydLh7vARM15Fn8tJy4yj/fgkU+3AWN8nWoOwceLNEB/yorBs1tjjSWEt3NIP7d
kcyHYmZ7XyUMSzlfdSVY+OoM1z63MoSCTwZJzZ5fI4ca+NtoxYny4unyM1q7QKwA
CisynJvGD5aI5bRgpjujlpw5IEuGqBZRjkLB0heOrPUlGEKkvaH2r9w/rGo8w4Is
ebz3OHBeVpB2AqbifMa+3cwZ9/IpRWUKUdnoqye5ySx1RHWmz3fjwerTDPzHWxJ8
YH8HORvuwUm+j/hXFvB3D8S754X+OEA8bgu/7dfIE1C330WDvVAP6EngCZKAI8W2
6u2SYXKPviqXciap5B4K4QHyUsiVruBIvymwTnz1+sharbRBOll7ZZKbBK1UNaCn
XO0Vt7NM5EbNEhjBlrArPGxIT0bFAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAD7W
3rD2n/PRT6U1TyInliTZ11+leG40+P+fhlXoajN8vwooCnoDZWQNXRYODekzC6t3
9jJWvbQyZnSL/jE81ixjN/CrHnrv1AmH63B3wgAaSYFja7UdfBE3rpb+ZsEZyjdu
54C1zsizwR85ZWUWoj22v3lzvmf0+FuqW9FxVREtZytePncfw40wFrQO9NX5QXo8
6ljZ18T7tNoeCv+C188SSbGNUDbC7VwTRCGACErbjAwX3ooQ5I2p3U3ipvTrXsnT
IYGeXwFqx7UjMtCYVJj8el+HlU1PZeyKZH/6j4HdseEZOvz8M/PSN8XjpStnhKQt
+dFmclEo68wU1KRnzUu38VynnKjSjeAZpws4eRqBr8rUeT8e52KbN07MLZ9q6GV7
V9MBERSIKNu7+PHIllvJCt3C3K0DGcq6ItNs5wOgtkXNI2RqovvtU2g6z1KdKthl
bVap4eh8WdVfYgFjTdiMFbLkFgZubNucyNXkKMPo79cnT1Wp1I3ZjNHuv7vtpXQD
WxfGZSsMM/ekgnR36wZFEqqt40bgie4RQJliIu1fWCVB6Y9kMb00dJ7otc8bIcVF
EZdTCbgdGvn91T9yN7yMXxoPmHq7WX6TG1hWVKLUAaiFAlJqFOg23fFj+6XlBD/G
/rGliGxn+1rvUywSv7oKVgTpbmwR65Fky2hDZWh5
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIE5TCCAs0CAQAwgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
BwwGQm9zdG9uMRMwEQYDVQQKDApFeGFtcGxlIENvMRAwDgYDVQQLDAd0ZWNob3Bz
MRAwDgYDVQQDDAdjbGllbnQyMSAwHgYJKoZIhvcNAQkBFhFjZXJ0c0BleGFtcGxl
LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO2ARFzN+hQgmnEj
OXHcOVjCPH6g/UNXwUNjtEUBg+EDTGliOC8If6ObFjW4tfIjwgGdhKt++92LRxDe
BauM8al7QK8yZhw7I7waqm0C4tIw4MdAlcRxZ0gEG7l5i9jU55yPpUcxZ1VE0VuH
ADgAosZtjltsBv03tq2Cf11jTEcaly4ze/8vDaAyl+M4u9FrflPnYoPmCiMBTz1j
1mdVtGsg2nGk+MA5RX9bMwWZq5bT9j2RG7PDMoc139SieQx4/5aVqIH628K7X0xE
/YydLh7vARM15Fn8tJy4yj/fgkU+3AWN8nWoOwceLNEB/yorBs1tjjSWEt3NIP7d
kcyHYmZ7XyUMSzlfdSVY+OoM1z63MoSCTwZJzZ5fI4ca+NtoxYny4unyM1q7QKwA
CisynJvGD5aI5bRgpjujlpw5IEuGqBZRjkLB0heOrPUlGEKkvaH2r9w/rGo8w4Is
ebz3OHBeVpB2AqbifMa+3cwZ9/IpRWUKUdnoqye5ySx1RHWmz3fjwerTDPzHWxJ8
YH8HORvuwUm+j/hXFvB3D8S754X+OEA8bgu/7dfIE1C330WDvVAP6EngCZKAI8W2
6u2SYXKPviqXciap5B4K4QHyUsiVruBIvymwTnz1+sharbRBOll7ZZKbBK1UNaCn
XO0Vt7NM5EbNEhjBlrArPGxIT0bFAgMBAAGgGTAXBgkqhkiG9w0BCQcxCgwIcGFz
c3dvcmQwDQYJKoZIhvcNAQELBQADggIBAGDn6DOovGaSpbe2PGetJrvQht2T6de8
cbnGCusQSjdqssUtjnKqV8hE4K8RsbrwWK6Gz6VR3s+ayVvm6JMNSf129UJEoOO5
f1KKWOB1ZuvIaxxdpWWSEyT2NWsnxPb4PVgRv+SjAkFlpfQdPqG+BDyd7PbjffTi
Yut3+AejTU6pkD9A82SyVUYP0hcSdnusclxeecBpvuBC1r1+ZmWMhgVHN9C13Bin
KPanEcwSP9GER9E5z38+mM6outSBTQ48+sSrfYXJgJe1kJ5U5swkTv0msoysOG7y
A9mn+upeL2+BI/9IkLswJygfDOUEQDdiafT9PAhJczKm6uLzNFSi5d+W+2VGMBoM
K3Ur5tg1Hom/yvkPBLteldNPySswJ0QTHtuhyyKsIx7pzy68YJtCIdaFCoOPMiEy
ME95l2Tp/G8g9GQbRNnRtBaNAirrzRTEpOxfIX0JZk/vouz7vDvnXLBZOwzaAWM3
0/f5uQD4YrY5qQ2Xl+Wq5ZySYi6afxhh0w9X72W3AKOgXuVKN0VUFOW0ani+tKuw
PLPwMRx12vgPUhNGfosTzTSOnTyI5yBqG4BtSHnR5k1DYLwTjdlGCr8jcA3u8sLP
sJX0u9+/JSaemlb2E6/T4pHwIot+l52DBnbe66ekwVoDf47smefapiYE7Gb7KRxA
0j8l/ryckQZk
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
[ req ]
default_bits = 4096
days = 9999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
x509_extensions = v3_ca
[ req_distinguished_name ]
C = US
ST = MA
L = Boston
O = Example Co
OU = techops
CN = client2
emailAddress = certs@example.com
[ req_attributes ]
challengePassword = password
[ v3_ca ]
authorityInfoAccess = @issuer_info
[ issuer_info ]
OCSP;URI.0 = http://ocsp.example.com/
caIssuers;URI.0 = http://example.com/ca.cert
// Example of the server https is taken from here: https://engineering.circle.com/https-authorized-certs-with-node-js-315e548354a2
// Conversion of client1-crt.pem to certificate.pfx: https://stackoverflow.com/a/38408666/4637638
const express = require('express')
var https = require('https')
const auth = require('basic-auth')
const appHttps = express()
const appAuthBasic = express()
const fs = require('fs')
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-crt.pem'),
ca: fs.readFileSync('ca-crt.pem'),
requestCert: true,
rejectUnauthorized: false
};
appHttps.get('/', (req, res) => {
const cert = req.connection.getPeerCertificate()
// The `req.client.authorized` flag will be true if the certificate is valid and was issued by a CA we white-listed
// earlier in `opts.ca`. We display the name of our user (CN = Common Name) and the name of the issuer, which is
// `localhost`.
if (req.client.authorized) {
res.send(`Hello ${cert.subject.CN}, your certificate was issued by ${cert.issuer.CN}!`)
// They can still provide a certificate which is not accepted by us. Unfortunately, the `cert` object will be an empty
// object instead of `null` if there is no certificate at all, so we have to check for a known field rather than
// truthiness.
} else if (cert.subject) {
res.status(403).send(`Sorry ${cert.subject.CN}, certificates from ${cert.issuer.CN} are not welcome here.`)
// And last, they can come to us with no certificate at all:
} else {
res.status(401).send(`Sorry, but you need to provide a client certificate to continue.`)
}
})
// Let's create our HTTPS server and we're ready to go.
https.createServer(options, appHttps).listen(4433)
// Ensure this is before any other middleware or routes
appAuthBasic.use((req, res, next) => {
let user = auth(req)
if (user === undefined || user['name'] !== 'user 1' || user['pass'] !== 'password 1') {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="Node"')
res.end('Unauthorized')
} else {
next()
}
})
appAuthBasic.get("/", (req, res) => {
res.send(`
<html>
<head>
</head>
<body>
<p>HELLO</p>
</body>
</html>
`);
})
appAuthBasic.listen(8081)
\ No newline at end of file
This diff is collapsed.
{
"name": "node_auth_basic",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"basic-auth": "latest",
"express": "latest",
"https": "latest"
}
}
-----BEGIN CERTIFICATE-----
MIIFjDCCA3SgAwIBAgIJALg+W/pyOZ5pMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD
VQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjETMBEGA1UECgwK
RXhhbXBsZSBDbzEQMA4GA1UECwwHdGVjaG9wczELMAkGA1UEAwwCY2ExIDAeBgkq
hkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMB4XDTE5MTAzMDIzMzQxOVoXDTIy
MDcyNTIzMzQxOVowgYgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
BwwGQm9zdG9uMRMwEQYDVQQKDApFeGFtcGxlIENvMRAwDgYDVQQLDAd0ZWNob3Bz
MRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0BCQEWEWNlcnRzQGV4YW1w
bGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6+4m+blS6NcS
ZcftDArQhd7ekeeZzfiedonAXybjJ+GkqtigKW2hUtHldWRswx56braUAJYUsj2I
Xh9y9/vWCGUGF9ZsiPTI28bZgbfwvyGaO0K4mLPGdvOvtXgbbw3uC6hU+sbiFF88
BgZdwnsjoP7wPHqyzJ8PQ7BM7jdflLFn1uULS+9fe/7gPRSXxvS26WC1IYK8gVqQ
JBXH2tO3ZSh8LygePjKUWQF4xsN8mttRYlahdhNIMb1ZgBnG4rFq8JOc5fUbrYIz
s+LLMRm8zn3GIZgp4BiK900RJGxDXtVnx6ce4fdj+4OsL8NW3JzBNB66unsQ1gkz
WZbAbaXN7HeUpnktuGfA+TdWrzMd8XXaMDHXj9Uh8NtjToBJ5hHkStSkHRxBnlyo
MvWXGubn+EfUC5nVBGnG/Yfb9caKlpgIHh164ScGKlFlV4W8VpoA1W0BwE/R/E/I
lo5wiX5DP2uxh8bC7J1UK7guDnGDZASWsqNxtCBuCmEx9L6ePlnQbuc/AA+QLdyS
z4wb0IGefS+et0BOJFj2/u28/A5N21swarTCxPm0rczXZfRhooM8/X6Z3Pw6E5ze
D1S/49V8qLwqwcwkJhnIJoqSj/cWNGVXRY2Tqu5536NvK3e5BvOPeULf0IKYDhUs
LxwgpQ07gntS7UHBSejmmmjs92IiQiECAwEAATANBgkqhkiG9w0BAQUFAAOCAgEA
JxbqWQynzigBoaR7DP6AtXzYC2RcVBQuwyBSy348ruiIeQy3Niwt5cuhFA/LVyZP
QI6KQTj2Qd0elAkeSp55nG/ZWmcszAF8aWrFRNUc0U85eUcZSyKP1eRblFgf2sMg
HrJY0w0Ust43jk+tWNCftSHL6+uxaKc0z18vFmpHIBtpecCHYaA2mEUTTS19mzSu
K816jEqDvwxUWRbC8aTLOKDS3w1OLBtwVQ8bBvKCbJv7I3AmWtGkmDdetBwEe9u4
lpC/7Rmm57/UG5P8Vy7lVGyOnxQaTE1FxxNWwq02Iy4gc1UAovYYBtgsg+XfnpL6
TUo/9gtjl5K6OMxS/8JJjCi7U8RqiZICGTvjUvl0ahUtjs9CHtruWPbQ7tpA+IWQ
k9U708R3TAILHtq1Po1cWTtezYqUokLVwQlvwWJOezuPWnz0v5VKuLX64Ot0HAjI
rB/VggCRRFbxseM22q3xYKGpERhvAnSjD6bAYP11MlCj/4FBflHDWgDjTvmwRW05
GW7rsTT+4omu/yQGRXSqFpaD1pYuoi1j0Lhtk/LCwQLE9bxPBUf0t8Ut+q5s0s0X
yXB1git1Aq09HZ1yJRfL//g/PWOu5lFhc8Xe4grrB3peRl2yHNiBNXQ1m1DmxCpL
oeM+rfdX4oDVWH5oFmyFGAUOdsZ1JgvaasFq2JRKryA=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIE5zCCAs8CAQAwgYgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
BwwGQm9zdG9uMRMwEQYDVQQKDApFeGFtcGxlIENvMRAwDgYDVQQLDAd0ZWNob3Bz
MRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0BCQEWEWNlcnRzQGV4YW1w
bGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6+4m+blS6NcS
ZcftDArQhd7ekeeZzfiedonAXybjJ+GkqtigKW2hUtHldWRswx56braUAJYUsj2I
Xh9y9/vWCGUGF9ZsiPTI28bZgbfwvyGaO0K4mLPGdvOvtXgbbw3uC6hU+sbiFF88
BgZdwnsjoP7wPHqyzJ8PQ7BM7jdflLFn1uULS+9fe/7gPRSXxvS26WC1IYK8gVqQ
JBXH2tO3ZSh8LygePjKUWQF4xsN8mttRYlahdhNIMb1ZgBnG4rFq8JOc5fUbrYIz
s+LLMRm8zn3GIZgp4BiK900RJGxDXtVnx6ce4fdj+4OsL8NW3JzBNB66unsQ1gkz
WZbAbaXN7HeUpnktuGfA+TdWrzMd8XXaMDHXj9Uh8NtjToBJ5hHkStSkHRxBnlyo
MvWXGubn+EfUC5nVBGnG/Yfb9caKlpgIHh164ScGKlFlV4W8VpoA1W0BwE/R/E/I
lo5wiX5DP2uxh8bC7J1UK7guDnGDZASWsqNxtCBuCmEx9L6ePlnQbuc/AA+QLdyS
z4wb0IGefS+et0BOJFj2/u28/A5N21swarTCxPm0rczXZfRhooM8/X6Z3Pw6E5ze
D1S/49V8qLwqwcwkJhnIJoqSj/cWNGVXRY2Tqu5536NvK3e5BvOPeULf0IKYDhUs
LxwgpQ07gntS7UHBSejmmmjs92IiQiECAwEAAaAZMBcGCSqGSIb3DQEJBzEKDAhw
YXNzd29yZDANBgkqhkiG9w0BAQsFAAOCAgEANu/fvD8Bq5ISbTQX42hTyHfe3caL
G7BDJdwTaBhzHcJFL0xbHDpDKvEhWgjzfP253x4EEx2tLHOCntj7CNBCYBq/oyWs
60ef7RH6/Lg+zo3wPO8iSV4hvjJrddwb7nlmZOFK0rGnpdTEQyvr+885/pyeP6a9
iMtZZL3/QIz2RN79nuOhh3J5G9SsrQhxw7Dk7zXIaSXdC/+f+lJnJZav6Q+9w8WD
a5sgx8jMTjL9TjA9jCh02P04MM4MD4YjwY9K13I9qWs3bhR4n43omlDFbMMQ/Es6
t+8hN1yxsokSi0iZhCCCeUZxfbCyN5z23DmHYcbkTwhKbqW4QJnJ3Xw9eYmPNC9Q
FxxZmj6A7N2+V07jXQjyhdNWCeTLoPEyoAAwtNi8SASG6olvgIygX0rhRwU8HvZt
u9gKh5vTg4Si4rNZ6DatHY/qlJUcaaqLpG2nI8bctkefH65if8k1iKhfPTxawtHk
ytrsyU+oQ2d6maBcEqfY6ui2j5O3U4yUVM+8RjppM/qrzqg9c3++tRfRMg0ZArQu
lXjA5KnQuNAeSDJmDpfOVoHAXM/uPte8pP9ZVO7MLBqhjkdXfF0fJxV6qX0/l0nt
gurXEbIv19qz91QkzI2MeM59c+IYTkxYZmkbFqf4rB2OJT5yUcsJ88R7zipc8zFa
CR1YgTG5mrlPW2c=
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA6+4m+blS6NcSZcftDArQhd7ekeeZzfiedonAXybjJ+Gkqtig
KW2hUtHldWRswx56braUAJYUsj2IXh9y9/vWCGUGF9ZsiPTI28bZgbfwvyGaO0K4
mLPGdvOvtXgbbw3uC6hU+sbiFF88BgZdwnsjoP7wPHqyzJ8PQ7BM7jdflLFn1uUL
S+9fe/7gPRSXxvS26WC1IYK8gVqQJBXH2tO3ZSh8LygePjKUWQF4xsN8mttRYlah
dhNIMb1ZgBnG4rFq8JOc5fUbrYIzs+LLMRm8zn3GIZgp4BiK900RJGxDXtVnx6ce
4fdj+4OsL8NW3JzBNB66unsQ1gkzWZbAbaXN7HeUpnktuGfA+TdWrzMd8XXaMDHX
j9Uh8NtjToBJ5hHkStSkHRxBnlyoMvWXGubn+EfUC5nVBGnG/Yfb9caKlpgIHh16
4ScGKlFlV4W8VpoA1W0BwE/R/E/Ilo5wiX5DP2uxh8bC7J1UK7guDnGDZASWsqNx
tCBuCmEx9L6ePlnQbuc/AA+QLdySz4wb0IGefS+et0BOJFj2/u28/A5N21swarTC
xPm0rczXZfRhooM8/X6Z3Pw6E5zeD1S/49V8qLwqwcwkJhnIJoqSj/cWNGVXRY2T
qu5536NvK3e5BvOPeULf0IKYDhUsLxwgpQ07gntS7UHBSejmmmjs92IiQiECAwEA
AQKCAgBMz++elEi7B/K0cn/p0MeNHj+Gb0ny9kPZQgYAtK92N4+eFAMpGclRJoc3
Tife6thfnU/YVQSN91yjkEelFzfa6dEvB5+0g0W10CrWgeV+xNjq/FEPXlB6P+Jw
CZec84MSBo8MSp4mlc78AyyZee/ipb3fYu89kXetyQNy91JGHfA51b50zY1f2F53
ZHH504iNuO+f5mmrD6ooJXM4+n8WDzVHQR9/joYf6EvDIrg5zrfTdXMB90sk7onq
G/pVqf+wLc8CS2fkeKSOp4MSDFgdPnO4Uksn67WqyEuReTIB+SbdqLp0RVAm/fqc
XlO0ZdC9QFf5CMI1fS9btqoVyMqe10+0T7mSRgzptsAoElZxt9/OPNW+7M0lGHJL
GWToqFTI7NZAppqiOw4YTGYF4krT/tBEv51NS83EytYJXKgE32z1n3HbxZVEQpJk
QZ7SqiLai+0MhWFiQhAu3GL1XqBqNiEOtPK2KZQaA/0FgOUU8fgrFdkuCZCow75D
9wKFUzXylH4qqgyyiH+/EU2aOnP0RthdK0mPdMO4QSZltaphxpzWmgwqfSPLqBUx
W1Lyw+FgM3Ux+40yFEuJgzAJzsmx3/C/+JG2UD6JXv7JYi1Dsats9I5fNBbTRTnb
JVbs5CbFTmYT3R2Eoj5f4VX1G5I4R4tRByYtuemLGC7euu7lAQKCAQEA+a2TkTNl
Nn3z0BBDgbMm5MM3bf/xEelrB4e+h1Chi6u0DmIVfnFXZDHZ/1xeLpTytGxj3tQ4
AC0Pkj26bjgz0oOqxO+WnuEL4+6NXAYTgcce5lPeWNZlDl1baoQwTNZT5Cumqyyy
Gs/ksUiB3zXxNbYDhYrbuFpV0Od2cfYusZCjHYVvsesteVRVTCjwH5qbo3o6IwHd
8T5L4FyvuzeDKnR+jcHgyPio5xg9lrChV2tVVC6DCStW1qvjZTaOVt9B/jkDfrXk
U78Hom2P2qv5b5iJy0aQ+d2hqPH3nW+x14rp1Ejac/FTVEKZLl4bgZRT/gbsepOQ
lBw/tC4IA14q8QKCAQEA8ed2Whd0uzAXWCjDj1xefEqAZN3l4ToPSvfxZkls3tgx
x8R9TlLmmEhtWjdl+68mhsSVoILVTTzFOBzbDaFNSjdyfTpf2927pofH5Sqy2x0d
HHE9XzXC3NjMDnwuv9TiVRq6S1uLmbSfPBVFYHGvJSdKj9fNIa09LehUaU0+qAes
FYr5W269Zpyz2e8pqmWC8jOIslbuqQxTJ3/2Xt4/s+BMMn0A6/iKByy915MnEyAi
aijdkeJWY9FHUXsj9Qpb0PQbp5MzMlSwOC5OaPQ7bbwoi2UKR9oG9I+BxuWdZWa4
z5OQBkKZBKopvy+UyxH6HwvCW/NX7k0DBDJVDhiqMQKCAQEAsnWBo2hD8LYIHfBx
//OIWjy6ktI8gdwAF0rMQTW9sfJRaXJsAIuMtl33flGMM+lcrN9IZw3y1RVgKtwa
NAvR5qcb2VWSqA8dC5cHzP2+1aT4jhLmO0NKygCqhbDkQRd0sQMORw1UZFuyD5FO
2rdYqFZnn/0HXXacHgxDGeOnrl0+aaxlkJsTTsSbjys3rq84jZmgkkMUWwl2/G/j
X4KnKyJHDpXEUIGDYGJwKxQmzjA2tkvkdxpWIGyNxVtAVBGRvt8Lg3cJM164Wz3K
c7c2O7Cg1P2kRCRJF1OT9CDQ0cpFpelI01Rrhi9wA7daG71kZ46VWmu9DFBArE22
hom5UQKCAQAXNLwu0lc5adijdW2lQBg0VjVQ99SIsbgr2fNHe7289wJ3hor6y4sh
irkq0WuwJFJO1WcBOevad/z3cBU3joTKnN0X1FTD09afmCD+BAWabYWQZ/CaRJ8H
7qhMr28Qqgx4W5MJjaOrwB8SdXvtT5qcttM5T1t3YpYe5E3MuENNfUbt3iIjulDj
Gh9Kxd26YfiY4Ya4jQxiHTOQ836gBTQZPmgw47sF6Bbdr1Ya6xvxgsCqbHcs+oiN
FNOBpo2BgVfjiLdqcP2VU3iAOzj8aomU8lr1XGELGYhXR7kMapSZ2KvcBezoHNVv
FB/jHl5oyLW06rzfc025J5wld+qe6pDRAoIBAHz4RLJ2WITZbCdDGn6nLnbI6jGd
RrYt2ZzMiz/QqAZV3WJP9vS+FDYDiU4IT7uCMuielbqNyB/3jd3ctxVD2GX3KbOh
WMdER9aHerafdFtxbOJXS/vkgjf8QBF54z1HhL+wnmSE+LaXI1R/WMJt7jBDbvcH
Ibfeyy+p76KO+qbEh07mHYjpCvhxaSeKaFX1vkJvXL4NiiZPNMemZWJkmrvr2k6E
WlmD61tDdYvEtMGZobPop/wJYVPE8yxivPtGpvdl7U8JJM++M8WTrMpWhxptelPL
6+egMoYXA/N1gTJNQ0w9eQEtNqXtQY/LQtWuUlhCanuT1eG/FyDGrpid8Bg=
-----END RSA PRIVATE KEY-----
[ req ]
default_bits = 4096
days = 9999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
x509_extensions = v3_ca
[ req_distinguished_name ]
C = US
ST = MA
L = Boston
O = Example Co
OU = techops
CN = localhost
emailAddress = certs@example.com
[ req_attributes ]
challengePassword = password
[ v3_ca ]
authorityInfoAccess = @issuer_info
[ issuer_info ]
OCSP;URI.0 = http://ocsp.example.com/
caIssuers;URI.0 = http://example.com/ca.cert
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment