@capgo/capacitor-ssl-pinning 8.1.9 → 8.1.10

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-ssl-pinning",
3
- "version": "8.1.9",
3
+ "version": "8.1.10",
4
4
  "description": "Capacitor SSL pinning plugin for Android and iOS that integrates with CapacitorHttp.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -51,6 +51,7 @@
51
51
  "watch": "tsc --watch",
52
52
  "prepublishOnly": "bun run build",
53
53
  "check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs",
54
+ "check:cap9-deprecated": "node scripts/check-cap9-deprecated.mjs",
54
55
  "prepare:certs": "bun run scripts/prepare-certs.mjs",
55
56
  "capacitor:sync:before": "bun run prepare:certs",
56
57
  "capacitor:update:before": "bun run prepare:certs",
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Capacitor 9 deprecated native API guard.
4
+ *
5
+ * Fails when plugin native sources still use APIs removed in Capacitor 9.
6
+ * Does not flag Cordova SwiftPM product dependencies (still required on Cap 8).
7
+ *
8
+ * Usage:
9
+ * node scripts/check-cap9-deprecated.mjs
10
+ * node scripts/check-cap9-deprecated.mjs --workspace
11
+ * node scripts/check-cap9-deprecated.mjs --dir path
12
+ */
13
+
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ const SKIP_DIRS = new Set([
19
+ "node_modules",
20
+ "dist",
21
+ "build",
22
+ ".build",
23
+ ".gradle",
24
+ "Pods",
25
+ "DerivedData",
26
+ ".swiftpm",
27
+ ".git",
28
+ "example-app",
29
+ ]);
30
+
31
+ /** @type {{ id: string, pattern: RegExp, exts: string[], ignoreLine?: RegExp }[]} */
32
+ const RULES = [
33
+ {
34
+ id: "hasOption",
35
+ pattern: /\bhasOption\s*\(/,
36
+ exts: [".java", ".kt", ".swift"],
37
+ },
38
+ {
39
+ id: "getConfigValue",
40
+ pattern: /\bgetConfigValue\s*\(/,
41
+ exts: [".java", ".kt", ".swift"],
42
+ },
43
+ {
44
+ id: "@NativePlugin",
45
+ pattern: /@NativePlugin\b/,
46
+ exts: [".java", ".kt"],
47
+ },
48
+ {
49
+ id: "saveCall",
50
+ pattern: /\bsaveCall\s*\(/,
51
+ exts: [".java", ".kt", ".swift"],
52
+ },
53
+ {
54
+ id: "getSavedCall",
55
+ pattern: /\bgetSavedCall\s*\(/,
56
+ exts: [".java", ".kt", ".swift"],
57
+ },
58
+ {
59
+ id: "freeSavedCall",
60
+ pattern: /\bfreeSavedCall\s*\(/,
61
+ exts: [".java", ".kt", ".swift"],
62
+ },
63
+ {
64
+ id: "releaseCall",
65
+ pattern: /\breleaseCall\s*\(/,
66
+ exts: [".java", ".kt", ".swift"],
67
+ ignoreLine: /\.releaseCall\s*\(\s*withID:/,
68
+ },
69
+ {
70
+ id: "pluginRequestPermission",
71
+ pattern: /\bpluginRequestPermissions?\s*\(/,
72
+ exts: [".java", ".kt"],
73
+ },
74
+ {
75
+ id: "pluginRequestAllPermissions",
76
+ pattern: /\bpluginRequestAllPermissions\s*\(/,
77
+ exts: [".java", ".kt"],
78
+ },
79
+ {
80
+ id: "hasDefinedPermissions",
81
+ pattern: /\bhasDefinedPermissions\s*\(/,
82
+ exts: [".java", ".kt"],
83
+ },
84
+ {
85
+ id: "CAPBridge",
86
+ pattern: /\bCAPBridge\./,
87
+ exts: [".swift"],
88
+ ignoreLine: /CAPBridgedPlugin/,
89
+ },
90
+ {
91
+ id: "CAPNotifications",
92
+ pattern: /\bCAPNotifications\b/,
93
+ exts: [".swift"],
94
+ },
95
+ ];
96
+
97
+ const CORDova_SPM_LINE =
98
+ /\.product\s*\(\s*name\s*:\s*"Cordova"\s*,\s*package\s*:\s*"capacitor-swift-pm"\s*\)/;
99
+
100
+ function readText(p) {
101
+ try {
102
+ return fs.readFileSync(p, "utf8");
103
+ } catch {
104
+ return "";
105
+ }
106
+ }
107
+
108
+ function exists(p) {
109
+ try {
110
+ fs.accessSync(p);
111
+ return true;
112
+ } catch {
113
+ return false;
114
+ }
115
+ }
116
+
117
+ function parseArgs(argv) {
118
+ const out = { dir: process.cwd(), workspace: false };
119
+ for (let i = 2; i < argv.length; i++) {
120
+ const a = argv[i];
121
+ if (a === "--workspace") {
122
+ out.workspace = true;
123
+ continue;
124
+ }
125
+ if (a === "--dir" || a === "--pluginDir") {
126
+ out.dir = path.resolve(argv[++i] || ".");
127
+ continue;
128
+ }
129
+ }
130
+ return out;
131
+ }
132
+
133
+ function walkFiles(rootDir, exts) {
134
+ const out = [];
135
+ const stack = [rootDir];
136
+ while (stack.length) {
137
+ const dir = stack.pop();
138
+ let entries;
139
+ try {
140
+ entries = fs.readdirSync(dir, { withFileTypes: true });
141
+ } catch {
142
+ continue;
143
+ }
144
+ for (const e of entries) {
145
+ if (e.isDirectory()) {
146
+ if (SKIP_DIRS.has(e.name)) continue;
147
+ stack.push(path.join(dir, e.name));
148
+ continue;
149
+ }
150
+ if (!e.isFile()) continue;
151
+ for (const ext of exts) {
152
+ if (e.name.endsWith(ext)) {
153
+ out.push(path.join(dir, e.name));
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ }
159
+ out.sort();
160
+ return out;
161
+ }
162
+
163
+ function collectScanRoots(pluginDir, cap) {
164
+ const roots = [];
165
+ if (cap.android) {
166
+ const androidMain = path.join(pluginDir, "android", "src", "main");
167
+ if (exists(androidMain)) roots.push(androidMain);
168
+ }
169
+ if (cap.ios) {
170
+ const iosSources = path.join(pluginDir, "ios", "Sources");
171
+ if (exists(iosSources)) roots.push(iosSources);
172
+ else {
173
+ const iosDir = path.join(pluginDir, "ios");
174
+ if (exists(iosDir)) roots.push(iosDir);
175
+ }
176
+ }
177
+ const packageSwift = path.join(pluginDir, "Package.swift");
178
+ if (exists(packageSwift)) roots.push(packageSwift);
179
+ return roots;
180
+ }
181
+
182
+ function scanFile(filePath, rule) {
183
+ const ext = path.extname(filePath);
184
+ if (!rule.exts.includes(ext)) return [];
185
+
186
+ const txt = readText(filePath);
187
+ const lines = txt.split(/\r?\n/);
188
+ const hits = [];
189
+ for (let i = 0; i < lines.length; i++) {
190
+ const line = lines[i];
191
+ if (filePath.endsWith("Package.swift") && CORDova_SPM_LINE.test(line)) {
192
+ continue;
193
+ }
194
+ if (rule.ignoreLine?.test(line)) continue;
195
+ if (rule.pattern.test(line)) {
196
+ hits.push({ line: i + 1, text: line.trim() });
197
+ }
198
+ }
199
+ return hits;
200
+ }
201
+
202
+ function listWorkspacePluginDirs(repoRoot) {
203
+ const packagesRoot = path.join(repoRoot, "packages");
204
+ if (!exists(packagesRoot)) return [];
205
+ return fs
206
+ .readdirSync(packagesRoot, { withFileTypes: true })
207
+ .filter((e) => e.isDirectory())
208
+ .map((e) => path.join(packagesRoot, e.name))
209
+ .filter((dir) => {
210
+ const pkgPath = path.join(dir, "package.json");
211
+ if (!exists(pkgPath)) return false;
212
+ try {
213
+ const pkg = JSON.parse(readText(pkgPath));
214
+ const cap = typeof pkg.capacitor === "object" && pkg.capacitor ? pkg.capacitor : {};
215
+ return Boolean(cap.android || cap.ios);
216
+ } catch {
217
+ return false;
218
+ }
219
+ })
220
+ .sort();
221
+ }
222
+
223
+ /**
224
+ * @returns {boolean} true when the plugin passes
225
+ */
226
+ function checkPluginDir(pluginDir) {
227
+ const pkgPath = path.join(pluginDir, "package.json");
228
+
229
+ if (!exists(pkgPath)) {
230
+ console.error(`[cap9-deprecated] ERROR: missing package.json in ${pluginDir}`);
231
+ return false;
232
+ }
233
+
234
+ let pkg;
235
+ try {
236
+ pkg = JSON.parse(readText(pkgPath));
237
+ } catch (e) {
238
+ console.error(`[cap9-deprecated] ERROR: invalid package.json (${pkgPath}): ${e?.message || e}`);
239
+ return false;
240
+ }
241
+
242
+ const cap = typeof pkg.capacitor === "object" && pkg.capacitor ? pkg.capacitor : {};
243
+ if (!cap.android && !cap.ios) {
244
+ return true;
245
+ }
246
+
247
+ const scanRoots = collectScanRoots(pluginDir, cap);
248
+ const allExts = [...new Set(RULES.flatMap((r) => r.exts))];
249
+ const files = [];
250
+ for (const root of scanRoots) {
251
+ if (root.endsWith("Package.swift")) {
252
+ files.push(root);
253
+ continue;
254
+ }
255
+ files.push(...walkFiles(root, allExts));
256
+ }
257
+
258
+ const violations = [];
259
+ for (const file of files) {
260
+ for (const rule of RULES) {
261
+ const hits = scanFile(file, rule);
262
+ for (const hit of hits) {
263
+ violations.push({
264
+ rule: rule.id,
265
+ file: path.relative(pluginDir, file),
266
+ line: hit.line,
267
+ text: hit.text,
268
+ });
269
+ }
270
+ }
271
+ }
272
+
273
+ if (violations.length) {
274
+ const relDir = path.relative(process.cwd(), pluginDir) || ".";
275
+ console.error(`[cap9-deprecated] FAIL in ${relDir}`);
276
+ for (const v of violations) {
277
+ console.error(`- ${v.rule}: ${v.file}:${v.line}: ${v.text}`);
278
+ }
279
+ return false;
280
+ }
281
+
282
+ return true;
283
+ }
284
+
285
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
286
+ const args = parseArgs(process.argv);
287
+
288
+ if (args.workspace) {
289
+ const pluginDirs = listWorkspacePluginDirs(repoRoot);
290
+ if (!pluginDirs.length) {
291
+ console.error("[cap9-deprecated] ERROR: no Capacitor plugin packages found under packages/*");
292
+ process.exit(2);
293
+ }
294
+ let failed = false;
295
+ for (const dir of pluginDirs) {
296
+ if (!checkPluginDir(dir)) failed = true;
297
+ }
298
+ if (failed) process.exit(1);
299
+ console.log(`[cap9-deprecated] OK (${pluginDirs.length} plugin package(s) scanned)`);
300
+ process.exit(0);
301
+ }
302
+
303
+ const ok = checkPluginDir(args.dir);
304
+ process.exit(ok ? 0 : 1);