@capgo/capacitor-ssl-pinning 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ package io.ionic.sslpinning;
2
+
3
+ import android.content.Context;
4
+ import com.getcapacitor.Bridge;
5
+ import com.getcapacitor.PluginConfig;
6
+ import java.io.InputStream;
7
+ import java.net.URL;
8
+ import java.security.KeyStore;
9
+ import java.security.cert.CertificateFactory;
10
+ import java.security.cert.X509Certificate;
11
+ import javax.net.ssl.SSLContext;
12
+ import javax.net.ssl.SSLSocketFactory;
13
+ import javax.net.ssl.TrustManagerFactory;
14
+
15
+ final class CertificateLoader {
16
+
17
+ private static final String CERTS_DIR = "public/certs";
18
+
19
+ private CertificateLoader() {}
20
+
21
+ static String[] getConfiguredCertPaths(final Bridge bridge) {
22
+ final PluginConfig config = bridge.getConfig().getPluginConfiguration("SSLPinning");
23
+ final String[] certs = config.getArray("certs", new String[0]);
24
+ return certs == null ? new String[0] : certs;
25
+ }
26
+
27
+ static String[] getExcludedDomains(final Bridge bridge) {
28
+ final PluginConfig config = bridge.getConfig().getPluginConfiguration("SSLPinning");
29
+ final String[] excludedDomains = config.getArray("excludedDomains", new String[0]);
30
+ return excludedDomains == null ? new String[0] : excludedDomains;
31
+ }
32
+
33
+ static SSLSocketFactory createSocketFactory(final Context context, final String[] configuredCertPaths) throws Exception {
34
+ final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
35
+ keyStore.load(null, null);
36
+
37
+ int index = 0;
38
+ for (String configuredCertPath : configuredCertPaths) {
39
+ final X509Certificate certificate = loadCertificate(context, configuredCertPath);
40
+ keyStore.setCertificateEntry("sslpinning-" + index, certificate);
41
+ index += 1;
42
+ }
43
+
44
+ final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
45
+ trustManagerFactory.init(keyStore);
46
+
47
+ final SSLContext sslContext = SSLContext.getInstance("TLS");
48
+ sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
49
+ return sslContext.getSocketFactory();
50
+ }
51
+
52
+ static boolean isExcluded(final URL requestUrl, final String[] excludedDomains) {
53
+ for (String rawExcludedDomain : excludedDomains) {
54
+ if (rawExcludedDomain == null || rawExcludedDomain.trim().isEmpty()) {
55
+ continue;
56
+ }
57
+
58
+ try {
59
+ final URL excludedUrl = new URL(rawExcludedDomain);
60
+ final int excludedPort = excludedUrl.getPort() == -1 ? excludedUrl.getDefaultPort() : excludedUrl.getPort();
61
+ final int requestPort = requestUrl.getPort() == -1 ? requestUrl.getDefaultPort() : requestUrl.getPort();
62
+
63
+ if (!excludedUrl.getProtocol().equalsIgnoreCase(requestUrl.getProtocol())) {
64
+ continue;
65
+ }
66
+ if (!excludedUrl.getHost().equalsIgnoreCase(requestUrl.getHost())) {
67
+ continue;
68
+ }
69
+ if (excludedPort != requestPort) {
70
+ continue;
71
+ }
72
+
73
+ final String excludedPath = excludedUrl.getPath() == null ? "" : excludedUrl.getPath();
74
+ if (excludedPath.isEmpty() || "/".equals(excludedPath)) {
75
+ return true;
76
+ }
77
+
78
+ final String requestPath = requestUrl.getPath() == null ? "" : requestUrl.getPath();
79
+ if (requestPath.startsWith(excludedPath)) {
80
+ return true;
81
+ }
82
+ } catch (Exception ignored) {
83
+ if (requestUrl.toString().startsWith(rawExcludedDomain)) {
84
+ return true;
85
+ }
86
+ }
87
+ }
88
+
89
+ return false;
90
+ }
91
+
92
+ private static X509Certificate loadCertificate(final Context context, final String configuredCertPath) throws Exception {
93
+ final String fileName = configuredCertPath.substring(configuredCertPath.lastIndexOf('/') + 1);
94
+ try (InputStream inputStream = context.getAssets().open(CERTS_DIR + "/" + fileName)) {
95
+ final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
96
+ return (X509Certificate) certificateFactory.generateCertificate(inputStream);
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,68 @@
1
+ package io.ionic.sslpinning;
2
+
3
+ import android.util.Log;
4
+ import com.getcapacitor.Bridge;
5
+ import com.getcapacitor.JSObject;
6
+ import com.getcapacitor.Plugin;
7
+ import com.getcapacitor.PluginCall;
8
+ import com.getcapacitor.PluginMethod;
9
+ import com.getcapacitor.annotation.CapacitorPlugin;
10
+ import java.net.URL;
11
+ import java.util.Arrays;
12
+ import javax.net.ssl.SSLSocketFactory;
13
+
14
+ @CapacitorPlugin(name = "SSLPinning")
15
+ public class SSLPinning extends Plugin {
16
+
17
+ private static final String TAG = "SSLPinning";
18
+ private static final Object LOCK = new Object();
19
+ private static SSLSocketFactory cachedSocketFactory;
20
+ private static String[] cachedCertPaths = new String[0];
21
+
22
+ @PluginMethod
23
+ public void getConfiguration(final PluginCall call) {
24
+ final Bridge bridge = getBridge();
25
+ final JSObject result = new JSObject();
26
+ final String[] certs = CertificateLoader.getConfiguredCertPaths(bridge);
27
+ final String[] excludedDomains = CertificateLoader.getExcludedDomains(bridge);
28
+ result.put("configured", certs.length > 0);
29
+ result.put("certs", certs);
30
+ result.put("excludedDomains", excludedDomains);
31
+ call.resolve(result);
32
+ }
33
+
34
+ @PluginMethod
35
+ public void getPluginVersion(final PluginCall call) {
36
+ final JSObject result = new JSObject();
37
+ result.put("version", "android");
38
+ call.resolve(result);
39
+ }
40
+
41
+ public Boolean isDomainExcluded(final Bridge bridge, final URL url) {
42
+ return CertificateLoader.isExcluded(url, CertificateLoader.getExcludedDomains(bridge));
43
+ }
44
+
45
+ public SSLSocketFactory getSSLSocketFactory(final Bridge bridge) {
46
+ final String[] certPaths = CertificateLoader.getConfiguredCertPaths(bridge);
47
+ if (certPaths.length == 0) {
48
+ return null;
49
+ }
50
+
51
+ synchronized (LOCK) {
52
+ if (cachedSocketFactory != null && Arrays.equals(certPaths, cachedCertPaths)) {
53
+ return cachedSocketFactory;
54
+ }
55
+
56
+ try {
57
+ cachedSocketFactory = CertificateLoader.createSocketFactory(bridge.getContext(), certPaths);
58
+ cachedCertPaths = Arrays.copyOf(certPaths, certPaths.length);
59
+ return cachedSocketFactory;
60
+ } catch (Exception exception) {
61
+ Log.e(TAG, "Failed to create SSL socket factory", exception);
62
+ cachedSocketFactory = null;
63
+ cachedCertPaths = new String[0];
64
+ return null;
65
+ }
66
+ }
67
+ }
68
+ }
File without changes
package/dist/docs.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "api": {
3
+ "name": "SSLPinningPlugin",
4
+ "slug": "sslpinningplugin",
5
+ "docs": "Capacitor API for inspecting SSL pinning configuration.\n\nNative enforcement is applied automatically to `CapacitorHttp` requests when:\n1. `plugins.CapacitorHttp.enabled` is `true`\n2. `plugins.SSLPinning.certs` contains at least one certificate",
6
+ "tags": [],
7
+ "methods": [
8
+ {
9
+ "name": "getConfiguration",
10
+ "signature": "() => Promise<SSLPinningConfigurationState>",
11
+ "parameters": [],
12
+ "returns": "Promise<SSLPinningConfigurationState>",
13
+ "tags": [],
14
+ "docs": "Returns the active native configuration visible to the plugin.",
15
+ "complexTypes": [
16
+ "SSLPinningConfigurationState"
17
+ ],
18
+ "slug": "getconfiguration"
19
+ },
20
+ {
21
+ "name": "getPluginVersion",
22
+ "signature": "() => Promise<PluginVersionResult>",
23
+ "parameters": [],
24
+ "returns": "Promise<PluginVersionResult>",
25
+ "tags": [],
26
+ "docs": "Returns the native implementation version marker.",
27
+ "complexTypes": [
28
+ "PluginVersionResult"
29
+ ],
30
+ "slug": "getpluginversion"
31
+ }
32
+ ],
33
+ "properties": []
34
+ },
35
+ "interfaces": [
36
+ {
37
+ "name": "SSLPinningConfigurationState",
38
+ "slug": "sslpinningconfigurationstate",
39
+ "docs": "Static SSL pinning configuration currently visible to the plugin.",
40
+ "tags": [],
41
+ "methods": [],
42
+ "properties": [
43
+ {
44
+ "name": "configured",
45
+ "tags": [],
46
+ "docs": "Whether at least one certificate is configured for native pinning.",
47
+ "complexTypes": [],
48
+ "type": "boolean"
49
+ },
50
+ {
51
+ "name": "certs",
52
+ "tags": [],
53
+ "docs": "Certificate paths from `capacitor.config.*` relative to the app root.",
54
+ "complexTypes": [],
55
+ "type": "string[]"
56
+ },
57
+ {
58
+ "name": "excludedDomains",
59
+ "tags": [],
60
+ "docs": "Fully-qualified URLs that should bypass SSL pinning.",
61
+ "complexTypes": [],
62
+ "type": "string[]"
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ "name": "PluginVersionResult",
68
+ "slug": "pluginversionresult",
69
+ "docs": "Plugin version payload.",
70
+ "tags": [],
71
+ "methods": [],
72
+ "properties": [
73
+ {
74
+ "name": "version",
75
+ "tags": [],
76
+ "docs": "Version identifier returned by the platform implementation.",
77
+ "complexTypes": [],
78
+ "type": "string"
79
+ }
80
+ ]
81
+ }
82
+ ],
83
+ "enums": [],
84
+ "typeAliases": [],
85
+ "pluginConfigs": []
86
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Plugin version payload.
3
+ */
4
+ export interface PluginVersionResult {
5
+ /**
6
+ * Version identifier returned by the platform implementation.
7
+ */
8
+ version: string;
9
+ }
10
+ /**
11
+ * Static SSL pinning configuration currently visible to the plugin.
12
+ */
13
+ export interface SSLPinningConfigurationState {
14
+ /**
15
+ * Whether at least one certificate is configured for native pinning.
16
+ */
17
+ configured: boolean;
18
+ /**
19
+ * Certificate paths from `capacitor.config.*` relative to the app root.
20
+ */
21
+ certs: string[];
22
+ /**
23
+ * Fully-qualified URLs that should bypass SSL pinning.
24
+ */
25
+ excludedDomains: string[];
26
+ }
27
+ /**
28
+ * Plugin configuration added under `plugins.SSLPinning` in `capacitor.config.*`.
29
+ */
30
+ export interface SSLPinningPluginConfig {
31
+ /**
32
+ * Certificate files relative to the application root.
33
+ *
34
+ * During `bunx cap sync`, this plugin copies them into `webDir/certs` so native runtimes can load them from
35
+ * the bundled web assets.
36
+ */
37
+ certs?: string[];
38
+ /**
39
+ * Fully-qualified URLs that should bypass pinning.
40
+ *
41
+ * Match is done by origin, and by path-prefix when the configured URL contains a path.
42
+ */
43
+ excludedDomains?: string[];
44
+ }
45
+ /**
46
+ * Capacitor API for inspecting SSL pinning configuration.
47
+ *
48
+ * Native enforcement is applied automatically to `CapacitorHttp` requests when:
49
+ * 1. `plugins.CapacitorHttp.enabled` is `true`
50
+ * 2. `plugins.SSLPinning.certs` contains at least one certificate
51
+ */
52
+ export interface SSLPinningPlugin {
53
+ /**
54
+ * Returns the active native configuration visible to the plugin.
55
+ */
56
+ getConfiguration(): Promise<SSLPinningConfigurationState>;
57
+ /**
58
+ * Returns the native implementation version marker.
59
+ */
60
+ getPluginVersion(): Promise<PluginVersionResult>;
61
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Plugin version payload.\n */\nexport interface PluginVersionResult {\n /**\n * Version identifier returned by the platform implementation.\n */\n version: string;\n}\n\n/**\n * Static SSL pinning configuration currently visible to the plugin.\n */\nexport interface SSLPinningConfigurationState {\n /**\n * Whether at least one certificate is configured for native pinning.\n */\n configured: boolean;\n\n /**\n * Certificate paths from `capacitor.config.*` relative to the app root.\n */\n certs: string[];\n\n /**\n * Fully-qualified URLs that should bypass SSL pinning.\n */\n excludedDomains: string[];\n}\n\n/**\n * Plugin configuration added under `plugins.SSLPinning` in `capacitor.config.*`.\n */\nexport interface SSLPinningPluginConfig {\n /**\n * Certificate files relative to the application root.\n *\n * During `bunx cap sync`, this plugin copies them into `webDir/certs` so native runtimes can load them from\n * the bundled web assets.\n */\n certs?: string[];\n\n /**\n * Fully-qualified URLs that should bypass pinning.\n *\n * Match is done by origin, and by path-prefix when the configured URL contains a path.\n */\n excludedDomains?: string[];\n}\n\n/**\n * Capacitor API for inspecting SSL pinning configuration.\n *\n * Native enforcement is applied automatically to `CapacitorHttp` requests when:\n * 1. `plugins.CapacitorHttp.enabled` is `true`\n * 2. `plugins.SSLPinning.certs` contains at least one certificate\n */\nexport interface SSLPinningPlugin {\n /**\n * Returns the active native configuration visible to the plugin.\n */\n getConfiguration(): Promise<SSLPinningConfigurationState>;\n\n /**\n * Returns the native implementation version marker.\n */\n getPluginVersion(): Promise<PluginVersionResult>;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { SSLPinningPlugin } from './definitions';
2
+ declare const SSLPinning: SSLPinningPlugin;
3
+ export * from './definitions';
4
+ export { SSLPinning };
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const SSLPinning = registerPlugin('SSLPinning', {
3
+ web: () => import('./web').then((m) => new m.SSLPinningWeb()),
4
+ });
5
+ export * from './definitions';
6
+ export { SSLPinning };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,UAAU,GAAG,cAAc,CAAmB,YAAY,EAAE;IAChE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;CAC9D,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { SSLPinningPlugin } from './definitions';\n\nconst SSLPinning = registerPlugin<SSLPinningPlugin>('SSLPinning', {\n web: () => import('./web').then((m) => new m.SSLPinningWeb()),\n});\n\nexport * from './definitions';\nexport { SSLPinning };\n"]}
@@ -0,0 +1,6 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { PluginVersionResult, SSLPinningConfigurationState, SSLPinningPlugin } from './definitions';
3
+ export declare class SSLPinningWeb extends WebPlugin implements SSLPinningPlugin {
4
+ getConfiguration(): Promise<SSLPinningConfigurationState>;
5
+ getPluginVersion(): Promise<PluginVersionResult>;
6
+ }
@@ -0,0 +1,16 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ export class SSLPinningWeb extends WebPlugin {
3
+ async getConfiguration() {
4
+ return {
5
+ configured: false,
6
+ certs: [],
7
+ excludedDomains: [],
8
+ };
9
+ }
10
+ async getPluginVersion() {
11
+ return {
12
+ version: 'web',
13
+ };
14
+ }
15
+ }
16
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC1C,KAAK,CAAC,gBAAgB;QACpB,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,EAAE;YACT,eAAe,EAAE,EAAE;SACpB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO;YACL,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { PluginVersionResult, SSLPinningConfigurationState, SSLPinningPlugin } from './definitions';\n\nexport class SSLPinningWeb extends WebPlugin implements SSLPinningPlugin {\n async getConfiguration(): Promise<SSLPinningConfigurationState> {\n return {\n configured: false,\n certs: [],\n excludedDomains: [],\n };\n }\n\n async getPluginVersion(): Promise<PluginVersionResult> {\n return {\n version: 'web',\n };\n }\n}\n"]}
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const SSLPinning = core.registerPlugin('SSLPinning', {
6
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.SSLPinningWeb()),
7
+ });
8
+
9
+ class SSLPinningWeb extends core.WebPlugin {
10
+ async getConfiguration() {
11
+ return {
12
+ configured: false,
13
+ certs: [],
14
+ excludedDomains: [],
15
+ };
16
+ }
17
+ async getPluginVersion() {
18
+ return {
19
+ version: 'web',
20
+ };
21
+ }
22
+ }
23
+
24
+ var web = /*#__PURE__*/Object.freeze({
25
+ __proto__: null,
26
+ SSLPinningWeb: SSLPinningWeb
27
+ });
28
+
29
+ exports.SSLPinning = SSLPinning;
30
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SSLPinning = registerPlugin('SSLPinning', {\n web: () => import('./web').then((m) => new m.SSLPinningWeb()),\n});\nexport * from './definitions';\nexport { SSLPinning };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SSLPinningWeb extends WebPlugin {\n async getConfiguration() {\n return {\n configured: false,\n certs: [],\n excludedDomains: [],\n };\n }\n async getPluginVersion() {\n return {\n version: 'web',\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;AAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AACjE,CAAC;;ACFM,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO;AACf,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,KAAK,EAAE,EAAE;AACrB,YAAY,eAAe,EAAE,EAAE;AAC/B,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO;AACf,YAAY,OAAO,EAAE,KAAK;AAC1B,SAAS;AACT,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,33 @@
1
+ var capacitorSSLPinning = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const SSLPinning = core.registerPlugin('SSLPinning', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.SSLPinningWeb()),
6
+ });
7
+
8
+ class SSLPinningWeb extends core.WebPlugin {
9
+ async getConfiguration() {
10
+ return {
11
+ configured: false,
12
+ certs: [],
13
+ excludedDomains: [],
14
+ };
15
+ }
16
+ async getPluginVersion() {
17
+ return {
18
+ version: 'web',
19
+ };
20
+ }
21
+ }
22
+
23
+ var web = /*#__PURE__*/Object.freeze({
24
+ __proto__: null,
25
+ SSLPinningWeb: SSLPinningWeb
26
+ });
27
+
28
+ exports.SSLPinning = SSLPinning;
29
+
30
+ return exports;
31
+
32
+ })({}, capacitorExports);
33
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SSLPinning = registerPlugin('SSLPinning', {\n web: () => import('./web').then((m) => new m.SSLPinningWeb()),\n});\nexport * from './definitions';\nexport { SSLPinning };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SSLPinningWeb extends WebPlugin {\n async getConfiguration() {\n return {\n configured: false,\n certs: [],\n excludedDomains: [],\n };\n }\n async getPluginVersion() {\n return {\n version: 'web',\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;IAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IACjE,CAAC;;ICFM,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO;IACf,YAAY,UAAU,EAAE,KAAK;IAC7B,YAAY,KAAK,EAAE,EAAE;IACrB,YAAY,eAAe,EAAE,EAAE;IAC/B,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO;IACf,YAAY,OAAO,EAAE,KAAK;IAC1B,SAAS;IACT,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,37 @@
1
+ import Capacitor
2
+ import Foundation
3
+
4
+ @objc(SSLPinningPlugin)
5
+ public class SSLPinningPlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "SSLPinningPlugin"
7
+ public let jsName = "SSLPinning"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "getConfiguration", returnType: CAPPluginReturnPromise),
10
+ CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
11
+ ]
12
+
13
+ @objc func getConfiguration(_ call: CAPPluginCall) {
14
+ let configuration = SSLPinningConfiguration.from(getConfig())
15
+ call.resolve(configuration.asJSObject)
16
+ }
17
+
18
+ @objc func getPluginVersion(_ call: CAPPluginCall) {
19
+ call.resolve([
20
+ "version": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "ios"
21
+ ])
22
+ }
23
+
24
+ @objc override public func handleWKWebViewURLAuthenticationChallenge(
25
+ _ challenge: URLAuthenticationChallenge,
26
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
27
+ ) -> Bool {
28
+ let configuration = SSLPinningConfiguration.from(getConfig())
29
+ guard configuration.configured else {
30
+ return false
31
+ }
32
+
33
+ let result = SSLPinningTrustEvaluator.evaluate(challenge: challenge, configuration: configuration)
34
+ completionHandler(result.0, result.1)
35
+ return true
36
+ }
37
+ }