@cap-kit/tls-fingerprint 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.
Files changed (51) hide show
  1. package/CapKitTlsFingerprint.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +25 -0
  4. package/README.md +427 -0
  5. package/android/build.gradle +103 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/java/io/capkit/settings/TLSFingerprintImpl.kt +333 -0
  8. package/android/src/main/java/io/capkit/settings/TLSFingerprintPlugin.kt +342 -0
  9. package/android/src/main/java/io/capkit/settings/config/TLSFingerprintConfig.kt +102 -0
  10. package/android/src/main/java/io/capkit/settings/error/TLSFingerprintError.kt +114 -0
  11. package/android/src/main/java/io/capkit/settings/error/TLSFingerprintErrorMessages.kt +27 -0
  12. package/android/src/main/java/io/capkit/settings/logger/TLSFingerprintLogger.kt +85 -0
  13. package/android/src/main/java/io/capkit/settings/model/TLSFingerprintResultModel.kt +32 -0
  14. package/android/src/main/java/io/capkit/settings/utils/TLSFingerprintUtils.kt +91 -0
  15. package/android/src/main/res/.gitkeep +0 -0
  16. package/dist/cli/fingerprint.js +163 -0
  17. package/dist/cli/fingerprint.js.map +1 -0
  18. package/dist/docs.json +386 -0
  19. package/dist/esm/cli/fingerprint.d.ts +1 -0
  20. package/dist/esm/cli/fingerprint.js +161 -0
  21. package/dist/esm/cli/fingerprint.js.map +1 -0
  22. package/dist/esm/definitions.d.ts +244 -0
  23. package/dist/esm/definitions.js +42 -0
  24. package/dist/esm/definitions.js.map +1 -0
  25. package/dist/esm/index.d.ts +13 -0
  26. package/dist/esm/index.js +11 -0
  27. package/dist/esm/index.js.map +1 -0
  28. package/dist/esm/version.d.ts +1 -0
  29. package/dist/esm/version.js +3 -0
  30. package/dist/esm/version.js.map +1 -0
  31. package/dist/esm/web.d.ts +33 -0
  32. package/dist/esm/web.js +47 -0
  33. package/dist/esm/web.js.map +1 -0
  34. package/dist/plugin.cjs +107 -0
  35. package/dist/plugin.cjs.map +1 -0
  36. package/dist/plugin.js +110 -0
  37. package/dist/plugin.js.map +1 -0
  38. package/ios/Sources/TLSFingerprintPlugin/TLSFingerprintDelegate.swift +365 -0
  39. package/ios/Sources/TLSFingerprintPlugin/TLSFingerprintImpl.swift +275 -0
  40. package/ios/Sources/TLSFingerprintPlugin/TLSFingerprintPlugin.swift +219 -0
  41. package/ios/Sources/TLSFingerprintPlugin/Version.swift +16 -0
  42. package/ios/Sources/TLSFingerprintPlugin/config/TLSFingerprintConfig.swift +114 -0
  43. package/ios/Sources/TLSFingerprintPlugin/error/TLSFingerprintError.swift +107 -0
  44. package/ios/Sources/TLSFingerprintPlugin/error/TLSFingerprintErrorMessages.swift +30 -0
  45. package/ios/Sources/TLSFingerprintPlugin/logger/TLSFingerprintLogger.swift +69 -0
  46. package/ios/Sources/TLSFingerprintPlugin/model/TLSFingerprintResult.swift +76 -0
  47. package/ios/Sources/TLSFingerprintPlugin/utils/TLSFingerprintUtils.swift +79 -0
  48. package/ios/Tests/TLSFingerprintPluginTests/TLSFingerprintPluginTests.swift +15 -0
  49. package/package.json +131 -0
  50. package/scripts/chmod.mjs +34 -0
  51. package/scripts/sync-version.mjs +68 -0
@@ -0,0 +1,79 @@
1
+ import Foundation
2
+ import Security
3
+ import CommonCrypto
4
+
5
+ struct TLSFingerprintUtils {
6
+ // MARK: - URL Helpers
7
+
8
+ static func httpsURL(from urlString: String) -> URL? {
9
+ guard let url = URL(string: urlString), url.scheme?.lowercased() == "https" else {
10
+ return nil
11
+ }
12
+ return url
13
+ }
14
+
15
+ // MARK: - Fingerprint Normalization
16
+
17
+ /**
18
+ Normalizes a fingerprint string by:
19
+ - Removing colon separators
20
+ - Removing all whitespace
21
+ - Converting to lowercase
22
+
23
+ Example:
24
+ "AA:BB:CC" → "aabbcc"
25
+ "AA BB CC" → "aabbcc"
26
+ */
27
+ static func normalizeFingerprint(_ fingerprint: String) -> String {
28
+ fingerprint
29
+ .replacingOccurrences(of: ":", with: "")
30
+ .replacingOccurrences(of: " ", with: "")
31
+ .lowercased()
32
+ }
33
+
34
+ /**
35
+ Validates that a fingerprint string is a valid SHA-256 hex format.
36
+
37
+ Valid fingerprint:
38
+ - Exactly 64 hexadecimal characters (after normalization)
39
+ - Contains only [a-f0-9]
40
+ */
41
+ static func isValidFingerprintFormat(_ fingerprint: String) -> Bool {
42
+ let normalized = normalizeFingerprint(fingerprint)
43
+ return normalized.count == 64 && normalized.allSatisfy { $0.isHexDigit }
44
+ }
45
+
46
+ /**
47
+ Validates a fingerprint and returns an error message if invalid, or nil if valid.
48
+ */
49
+ static func validateFingerprint(_ fingerprint: String) -> String? {
50
+ let trimmed = fingerprint.trimmingCharacters(in: .whitespacesAndNewlines)
51
+ if trimmed.isEmpty {
52
+ return "Fingerprint cannot be blank"
53
+ }
54
+ let normalized = normalizeFingerprint(fingerprint)
55
+ if normalized.count != 64 {
56
+ return "Invalid fingerprint: must be 64 hex characters"
57
+ }
58
+ if !normalized.allSatisfy({ $0.isHexDigit }) {
59
+ return "Invalid fingerprint: must contain only hex characters [a-f0-9]"
60
+ }
61
+ return nil
62
+ }
63
+
64
+ // MARK: - Certificate Helpers
65
+
66
+ static func sha256Fingerprint(from certificate: SecCertificate) -> String {
67
+ let certData = SecCertificateCopyData(certificate) as Data
68
+ var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
69
+ certData.withUnsafeBytes { bytes in
70
+ _ = CC_SHA256(bytes.baseAddress, CC_LONG(certData.count), &hash)
71
+ }
72
+ return hash.map { String(format: "%02x", $0) }.joined()
73
+ }
74
+
75
+ static func leafCertificate(from trust: SecTrust) -> SecCertificate? {
76
+ guard SecTrustGetCertificateCount(trust) > 0 else { return nil }
77
+ return SecTrustGetCertificateAtIndex(trust, 0)
78
+ }
79
+ }
@@ -0,0 +1,15 @@
1
+ import XCTest
2
+ @testable import TLSFingerprint
3
+
4
+ /**
5
+ Basic functional tests for the TLSFingerprint plugin native implementation.
6
+
7
+ These tests validate the core behavior of the implementation
8
+ independently from the Capacitor bridge.
9
+ */
10
+ class TLSFingerprintPluginTests: XCTestCase {
11
+ func testInstantiation() {
12
+ let implementation = TLSFingerprintImpl()
13
+ XCTAssertTrue(true)
14
+ }
15
+ }
package/package.json ADDED
@@ -0,0 +1,131 @@
1
+ {
2
+ "name": "@cap-kit/tls-fingerprint",
3
+ "version": "8.0.0",
4
+ "description": "Runtime TLS leaf certificate SHA-256 fingerprint validation plugin for Capacitor (iOS & Android)",
5
+ "type": "module",
6
+ "private": false,
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=24.0.0",
10
+ "pnpm": ">=10.0.0"
11
+ },
12
+ "main": "dist/plugin.cjs",
13
+ "module": "dist/esm/index.js",
14
+ "types": "dist/esm/index.d.ts",
15
+ "unpkg": "dist/plugin.js",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/esm/index.d.ts",
19
+ "import": "./dist/esm/index.js",
20
+ "require": "./dist/plugin.cjs"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "files": [
25
+ "android/src/main/",
26
+ "android/build.gradle",
27
+ "dist/",
28
+ "ios/Sources",
29
+ "ios/Tests",
30
+ "Package.swift",
31
+ "CapKitTlsFingerprint.podspec",
32
+ "LICENSE",
33
+ "README.md",
34
+ "bin/",
35
+ "scripts/"
36
+ ],
37
+ "author": "CapKit Team",
38
+ "funding": {
39
+ "type": "github",
40
+ "url": "https://github.com/sponsors/cap-kit"
41
+ },
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/cap-kit/capacitor-plugins.git",
46
+ "directory": "packages/tls-fingerprint"
47
+ },
48
+ "bugs": {
49
+ "url": "https://github.com/cap-kit/capacitor-plugins/issues"
50
+ },
51
+ "homepage": "https://github.com/cap-kit/capacitor-plugins/tree/main/packages/tls-fingerprint#readme",
52
+ "keywords": [
53
+ "capacitor",
54
+ "capacitor-plugin",
55
+ "mobile",
56
+ "native",
57
+ "cap-kit",
58
+ "ios",
59
+ "android",
60
+ "tls",
61
+ "https",
62
+ "certificate",
63
+ "certificate-fingerprint",
64
+ "tls-fingerprint",
65
+ "sha256",
66
+ "leaf-certificate",
67
+ "security"
68
+ ],
69
+ "bin": {
70
+ "cap-kit-tls-fingerprint": "./dist/cli/fingerprint.js"
71
+ },
72
+ "publishConfig": {
73
+ "access": "public"
74
+ },
75
+ "dependencies": {
76
+ "yargs": "^18.0.0"
77
+ },
78
+ "devDependencies": {
79
+ "@capacitor/android": "^8.1.0",
80
+ "@capacitor/cli": "^8.1.0",
81
+ "@capacitor/core": "^8.1.0",
82
+ "@capacitor/docgen": "^0.3.1",
83
+ "@capacitor/ios": "^8.1.0",
84
+ "@eslint/eslintrc": "^3.3.3",
85
+ "@eslint/js": "^9.39.2",
86
+ "eslint": "^9.39.2",
87
+ "eslint-plugin-import": "^2.32.0",
88
+ "@types/node": "^25.3.0",
89
+ "@types/yargs": "^17.0.35",
90
+ "globals": "^17.3.0",
91
+ "prettier": "^3.8.1",
92
+ "prettier-plugin-java": "^2.8.1",
93
+ "rimraf": "^6.1.3",
94
+ "rollup": "^4.57.1",
95
+ "swiftlint": "^2.0.0",
96
+ "typescript": "~5.9.3",
97
+ "typescript-eslint": "^8.56.0"
98
+ },
99
+ "peerDependencies": {
100
+ "@capacitor/core": "^8.1.0"
101
+ },
102
+ "capacitor": {
103
+ "ios": {
104
+ "src": "ios"
105
+ },
106
+ "android": {
107
+ "src": "android"
108
+ }
109
+ },
110
+ "scripts": {
111
+ "verify": "pnpm run verify:ios && pnpm run verify:android && pnpm run verify:web",
112
+ "verify:ios": "node ./scripts/sync-version.mjs && xcodebuild -scheme CapKitTlsFingerprint -destination generic/platform=iOS",
113
+ "verify:android": "cd android && ./gradlew clean build && cd ..",
114
+ "verify:web": "pnpm run build",
115
+ "lint:android": "cd android && ./gradlew ktlintCheck",
116
+ "fmt:android": "cd android && ./gradlew ktlintFormat",
117
+ "lint": "pnpm run eslint . && pnpm run swiftlint lint --strict || true && pnpm run lint:android || true",
118
+ "format:check": "prettier --check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
119
+ "format": "eslint --fix . && prettier --write \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java && pnpm run swiftlint --fix --format && pnpm run fmt:android",
120
+ "eslint": "eslint",
121
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
122
+ "swiftlint": "node-swiftlint lint ios/Sources",
123
+ "docgen": "docgen --api TLSFingerprintPlugin --output-readme README.md --output-json dist/docs.json",
124
+ "build": "node ./scripts/sync-version.mjs && pnpm run clean && pnpm run docgen && tsc && rollup -c rollup.config.mjs && node scripts/chmod.mjs",
125
+ "clean": "rimraf ./dist",
126
+ "watch": "tsc --watch",
127
+ "test": "pnpm run verify",
128
+ "removePacked": "rimraf -g cap-kit-tls-fingerprint-*.tgz",
129
+ "publish:locally": "pnpm run removePacked && pnpm run build && pnpm pack"
130
+ }
131
+ }
@@ -0,0 +1,34 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ // Reconstruct __dirname, which does not exist in ESM
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ // Correct path to the compiled CLI
10
+ const cliPath = path.resolve(__dirname, '../dist/cli/fingerprint.js');
11
+
12
+ try {
13
+ if (fs.existsSync(cliPath)) {
14
+ // 1. Read the file contents
15
+ let content = fs.readFileSync(cliPath, 'utf8');
16
+
17
+ // 2. Add shebang if missing
18
+ if (!content.startsWith('#!/usr/bin/env node')) {
19
+ content = '#!/usr/bin/env node\n' + content;
20
+ fs.writeFileSync(cliPath, content);
21
+ console.log('✅ Shebang added to CLI.');
22
+ }
23
+
24
+ // 3. Make the file executable
25
+ fs.chmodSync(cliPath, '755');
26
+ console.log('✅ CLI permissions set to 755.');
27
+ } else {
28
+ console.error(`❌ CLI file not found at: ${cliPath}`);
29
+ // Do not fail the build if the file does not exist yet, just warn
30
+ }
31
+ } catch (err) {
32
+ console.error('❌ Error setting permissions:', err);
33
+ process.exit(1);
34
+ }
@@ -0,0 +1,68 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ // 1. Setup __dirname equivalent for ES Modules
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ // 2. Load the plugin's package.json
10
+ const pkgPath = path.join(__dirname, '../package.json');
11
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
12
+
13
+ // 3. Automatically find the iOS source directory
14
+ // Capacitor standard structure: ios/Sources/<PluginName>
15
+ const sourcesDir = path.join(__dirname, '../ios/Sources');
16
+
17
+ if (!fs.existsSync(sourcesDir)) {
18
+ console.warn('⚠️ [CapKit] ios/Sources directory not found. Skipping Version.swift generation.');
19
+ process.exit(0);
20
+ }
21
+
22
+ const pluginFolderName = fs.readdirSync(sourcesDir).find((f) => fs.statSync(path.join(sourcesDir, f)).isDirectory());
23
+
24
+ if (!pluginFolderName) {
25
+ console.error('❌ [CapKit] Could not find a source directory in ios/Sources');
26
+ process.exit(1);
27
+ }
28
+
29
+ const versionFilePath = path.join(sourcesDir, pluginFolderName, 'Version.swift');
30
+ const webVersionFilePath = path.join(__dirname, '../src/version.ts');
31
+
32
+ const content = `// This file is automatically generated. Do not modify manually.
33
+ import Foundation
34
+
35
+ /**
36
+ Container for the plugin's version information.
37
+ This enum provides a centralized, single source of truth for the native
38
+ version string, synchronized directly from the project's 'package.json'.
39
+ It ensures parity across JavaScript, Android, and iOS platforms.
40
+ */
41
+ public enum PluginVersion {
42
+ /**
43
+ The semantic version string of the plugin.
44
+ Value synchronized from package.json: "${pkg.version}"
45
+ */
46
+ public static let number = "${pkg.version}"
47
+ }
48
+ `;
49
+
50
+ try {
51
+ fs.writeFileSync(versionFilePath, content);
52
+ console.log(`✅ [CapKit] Version.swift updated to v${pkg.version} in ${pluginFolderName}`);
53
+ } catch (err) {
54
+ console.error('❌ [CapKit] Error generating Version.swift:', err);
55
+ process.exit(1);
56
+ }
57
+
58
+ const webVersionContent = `// This file is automatically generated. Do not modify manually.
59
+ export const PLUGIN_VERSION = '${pkg.version}';
60
+ `;
61
+
62
+ try {
63
+ fs.writeFileSync(webVersionFilePath, webVersionContent);
64
+ console.log(`✅ [CapKit] src/version.ts updated to v${pkg.version}`);
65
+ } catch (err) {
66
+ console.error('❌ [CapKit] Error generating src/version.ts:', err);
67
+ process.exit(1);
68
+ }