@intincrab/updiff 0.1.1 → 0.2.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.
- package/README.md +64 -18
- package/dist/agent.js +1 -1
- package/dist/bundle.js +63 -5
- package/dist/cask-history.js +216 -0
- package/dist/cask.js +79 -0
- package/dist/codesign.js +41 -0
- package/dist/commands.js +156 -5
- package/dist/diff.js +99 -3
- package/dist/extensions.js +453 -0
- package/dist/fetch.js +81 -0
- package/dist/hosts.js +17 -0
- package/dist/installer.js +177 -0
- package/dist/macho.js +35 -0
- package/dist/pkg-report.js +211 -0
- package/dist/pkg.js +211 -0
- package/dist/report.js +31 -2
- package/dist/store.js +21 -0
- package/dist/util.js +34 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/report.js
CHANGED
|
@@ -31,11 +31,14 @@ export function renderText(report, options = {}) {
|
|
|
31
31
|
for (const f of group) {
|
|
32
32
|
lines.push(` ${p.sev(sev, CHANGE_MARK[f.change])} ${f.title}`);
|
|
33
33
|
if (f.detail)
|
|
34
|
-
|
|
34
|
+
for (const d of clip(f.detail, max).split('\n'))
|
|
35
|
+
lines.push(` ${d}`);
|
|
35
36
|
if (f.where?.length)
|
|
36
37
|
lines.push(p.dim(` at ${f.where.join(', ')}`));
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
for (const note of report.notes ?? [])
|
|
41
|
+
lines.push('', p.dim(`Note: ${note}`));
|
|
39
42
|
if (report.findings.some((f) => f.category === 'host'))
|
|
40
43
|
lines.push('', p.dim(HOSTNAME_CAVEAT));
|
|
41
44
|
return lines.join('\n') + '\n';
|
|
@@ -62,13 +65,17 @@ export function renderMarkdown(report) {
|
|
|
62
65
|
lines.push(`## ${SEVERITY_LABEL[sev]}`, '');
|
|
63
66
|
for (const f of group) {
|
|
64
67
|
lines.push(`- ${CHANGE_MARK[f.change] === '+' ? 'Added' : CHANGE_MARK[f.change] === '-' ? 'Removed' : 'Changed'}: **${mdEscape(f.title)}**`);
|
|
65
|
-
if (f.detail)
|
|
68
|
+
if (f.detail?.includes('\n'))
|
|
69
|
+
lines.push('', ' ```diff', ...f.detail.split('\n').map((d) => ` ${d}`), ' ```', '');
|
|
70
|
+
else if (f.detail)
|
|
66
71
|
lines.push(` ${mdEscape(f.detail)}`);
|
|
67
72
|
if (f.where?.length)
|
|
68
73
|
lines.push(` <sub>${f.where.map((w) => `\`${w}\``).join(', ')}</sub>`);
|
|
69
74
|
}
|
|
70
75
|
lines.push('');
|
|
71
76
|
}
|
|
77
|
+
for (const note of report.notes ?? [])
|
|
78
|
+
lines.push(`> Note: ${mdEscape(note)}`, '');
|
|
72
79
|
if (report.findings.some((f) => f.category === 'host'))
|
|
73
80
|
lines.push(`> ${HOSTNAME_CAVEAT}`, '');
|
|
74
81
|
lines.push('<sub>Generated by updiff. Static inspection only: the app was not run.</sub>', '');
|
|
@@ -99,13 +106,35 @@ export function renderScan(s, options = {}) {
|
|
|
99
106
|
lines.push(`Signing ${sig.status}${sig.teamId ? `, team ${sig.teamId}` : ''}${sig.authorities[0] ? ` (${sig.authorities[0]})` : ''}${sig.hardenedRuntime ? ', hardened runtime' : ', no hardened runtime'}`);
|
|
100
107
|
const ents = Object.keys(main?.entitlements ?? {});
|
|
101
108
|
const sandboxed = main?.entitlements?.['com.apple.security.app-sandbox'] === true;
|
|
109
|
+
if (s.notarization) {
|
|
110
|
+
const n = s.notarization;
|
|
111
|
+
const stapled = n.stapled === undefined ? '' : n.stapled ? ', ticket stapled' : ', ticket not stapled';
|
|
112
|
+
if (n.error)
|
|
113
|
+
lines.push(`Gatekeeper could not verify the signature: ${n.error}`);
|
|
114
|
+
else
|
|
115
|
+
lines.push(`Gatekeeper ${n.assessment}${n.source ? ` (${n.source})` : ''}${stapled}`);
|
|
116
|
+
}
|
|
117
|
+
if (s.info.appStoreReceipt)
|
|
118
|
+
lines.push('App Store yes (bundle has a Mac App Store receipt)');
|
|
102
119
|
lines.push(`Sandbox ${sandboxed ? 'yes' : 'no'}`);
|
|
103
120
|
lines.push(`Entitlements ${ents.length ? ents.join(', ') : 'none'}`);
|
|
104
121
|
const privacy = Object.keys(s.info.privacyUsage);
|
|
105
122
|
lines.push(`Privacy asks ${privacy.length ? privacy.map((k) => k.replace(/^NS/, '').replace(/UsageDescription$/, '')).join(', ') : 'none'}`);
|
|
106
123
|
lines.push(`URL schemes ${s.info.urlSchemes.length ? s.info.urlSchemes.join(', ') : 'none'}`);
|
|
124
|
+
const sparkle = s.code.some((c) => c.kind === 'framework' && c.path.endsWith('/Sparkle.framework'));
|
|
107
125
|
if (s.info.sparkleFeedUrl)
|
|
108
126
|
lines.push(`Update feed ${s.info.sparkleFeedUrl}`);
|
|
127
|
+
for (const [i, url] of (s.info.sparkleFeedsInCode ?? []).entries())
|
|
128
|
+
lines.push(`${i === 0 && !s.info.sparkleFeedUrl ? 'Update feed ' : ' '} ${url} (in code)`);
|
|
129
|
+
if (sparkle && !s.info.sparkleFeedUrl && !s.info.sparkleFeedsInCode?.length) {
|
|
130
|
+
lines.push('Update feed Sparkle is bundled, but no feed was found (it may be built at runtime)');
|
|
131
|
+
}
|
|
132
|
+
if (s.local?.sparkleFeedInDefaults)
|
|
133
|
+
lines.push(` ${s.local.sparkleFeedInDefaults} (set in this Mac's preferences)`);
|
|
134
|
+
if (s.local && (s.local.sparkleAutomaticChecks !== undefined || s.local.sparkleAutomaticallyUpdate !== undefined)) {
|
|
135
|
+
const onOff = (v) => (v === undefined ? 'default' : v ? 'on' : 'off');
|
|
136
|
+
lines.push(`This Mac automatic update checks ${onOff(s.local.sparkleAutomaticChecks)}, automatic install ${onOff(s.local.sparkleAutomaticallyUpdate)}`);
|
|
137
|
+
}
|
|
109
138
|
const counts = new Map();
|
|
110
139
|
for (const c of s.code)
|
|
111
140
|
if (c.kind !== 'main')
|
package/dist/store.js
CHANGED
|
@@ -81,6 +81,27 @@ export class Store {
|
|
|
81
81
|
await Promise.all(drop.map((d) => rm(d.file, { force: true })));
|
|
82
82
|
return drop.length;
|
|
83
83
|
}
|
|
84
|
+
get extensionsDir() {
|
|
85
|
+
return join(this.home, 'extensions');
|
|
86
|
+
}
|
|
87
|
+
async saveExtensions(snapshot) {
|
|
88
|
+
await mkdir(this.extensionsDir, { recursive: true });
|
|
89
|
+
const file = join(this.extensionsDir, `${snapshot.takenAt.replace(/[:.]/g, '-')}.json`);
|
|
90
|
+
await writeFile(file, JSON.stringify(snapshot));
|
|
91
|
+
const all = (await readdir(this.extensionsDir)).filter((n) => n.endsWith('.json')).sort();
|
|
92
|
+
await Promise.all(all.slice(0, Math.max(0, all.length - 10)).map((n) => rm(join(this.extensionsDir, n), { force: true })));
|
|
93
|
+
return file;
|
|
94
|
+
}
|
|
95
|
+
async latestExtensions() {
|
|
96
|
+
try {
|
|
97
|
+
const all = (await readdir(this.extensionsDir)).filter((n) => n.endsWith('.json')).sort();
|
|
98
|
+
const last = all.at(-1);
|
|
99
|
+
return last ? JSON.parse(await readFile(join(this.extensionsDir, last), 'utf8')) : undefined;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
84
105
|
async saveReport(bundleId, fromVersion, toVersion, ext, content) {
|
|
85
106
|
const dir = join(this.reportsDir, safe(bundleId));
|
|
86
107
|
await mkdir(dir, { recursive: true });
|
package/dist/util.js
CHANGED
|
@@ -37,3 +37,37 @@ export function stableJson(v) {
|
|
|
37
37
|
}
|
|
38
38
|
return JSON.stringify(v);
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Line diff of two texts as "+ line" / "- line" entries (unchanged lines left out).
|
|
42
|
+
* Uses a longest-common-subsequence table, so keep inputs to a few thousand lines.
|
|
43
|
+
*/
|
|
44
|
+
export function lineDiff(before, after) {
|
|
45
|
+
const a = before.split('\n');
|
|
46
|
+
const b = after.split('\n');
|
|
47
|
+
if (a.length * b.length > 4_000_000)
|
|
48
|
+
return [`(too long to compare line by line: ${a.length} → ${b.length} lines)`];
|
|
49
|
+
const lcs = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
|
|
50
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
51
|
+
for (let j = b.length - 1; j >= 0; j--) {
|
|
52
|
+
lcs[i][j] = a[i] === b[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const out = [];
|
|
56
|
+
let i = 0;
|
|
57
|
+
let j = 0;
|
|
58
|
+
while (i < a.length && j < b.length) {
|
|
59
|
+
if (a[i] === b[j]) {
|
|
60
|
+
i++;
|
|
61
|
+
j++;
|
|
62
|
+
}
|
|
63
|
+
else if (lcs[i + 1][j] >= lcs[i][j + 1])
|
|
64
|
+
out.push(`- ${a[i++]}`);
|
|
65
|
+
else
|
|
66
|
+
out.push(`+ ${b[j++]}`);
|
|
67
|
+
}
|
|
68
|
+
while (i < a.length)
|
|
69
|
+
out.push(`- ${a[i++]}`);
|
|
70
|
+
while (j < b.length)
|
|
71
|
+
out.push(`+ ${b[j++]}`);
|
|
72
|
+
return out;
|
|
73
|
+
}
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const TOOL_NAME = 'updiff';
|
|
2
|
-
export const TOOL_VERSION = '0.
|
|
2
|
+
export const TOOL_VERSION = '0.2.0';
|
package/package.json
CHANGED