@bobfrankston/rmfmail 1.2.313 → 1.2.315

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/.commitmsg CHANGED
@@ -1,22 +1,17 @@
1
- Trusted lists: the action beside the warning, and a way to undo it
1
+ Self-spoof: the From domain's own SPF or DKIM pass is proof, DMARC verdict or not
2
2
 
3
- Bob 2026-09-09, after v1.2.312: "it would be nice to have an [approve
4
- this list] on the red warning banner" and "how would I undo an approval".
3
+ Follow-up to v1.2.314 (which vetoed the self-spoof finding on a DMARC pass).
4
+ The AMW list (berglist.com) publishes no DMARC policy, so its posts carry
5
+ no dmarc= verdict at all — but iecc.com recorded spf=pass for
6
+ amw-bounces@berglist.com and dkim=pass d=berglist.com, which is the very
7
+ evidence DMARC would have aligned on. The dkim=fail beside them was the
8
+ gmail.com author signature the list broke, and the post was red as a spoof
9
+ of the list's own address (Delivered-To). New alignedPass() in trust.ts:
10
+ a verified signature for the From domain, or an SPF pass for an envelope at
11
+ the From domain, computed as DMARC's relaxed alignment; a forger's pass for
12
+ their own domain clears nothing (tested).
5
13
 
6
- An unflagged list post has no banner the spam-score chip IS the warning
7
- so "Trust the ‹List-Id› list" now sits beside the chip as a button, the
8
- same write as the banner button and the From-menu item. The red (danger)
9
- banner still carries no list button on purpose: over the last 120 days
10
- every proved-list post that stayed red (123 of 1,386 flagged list posts)
11
- was a phishing or malware URL listing on a throwaway domain that signs
12
- its own mail, and trusting a list never clears those, so a button there
13
- would be one that does nothing.
14
-
15
- Undo: once a list is trusted the chip and banner are gone, so the From
16
- address's right-click item is now offered on every proved post and reads
17
- "Stop trusting the ‹List-Id› mailing list" when the list is trusted — the
18
- toggle the write always was, finally reachable. The action checks that
19
- the answer went the way it asked and reports otherwise. docs/allowlist.md
20
- header reworded: the "do not edit" notice is about the .md itself;
21
- hand-editing allowlist.jsonc is fine and is how a sender or intermediary
22
- approval is undone until those get an undo of their own.
14
+ Store, last 120 days, messages whose From is their own Delivered-To: 977;
15
+ self-spoof findings 35 before v1.2.314, 20 after it, 15 now. The 15 that
16
+ remain are the sextortion, "failed to deliver", NDA-review and
17
+ document-share phishes the check exists for. mailx-types 0.1.91.
@@ -40,10 +40,14 @@ tests/trust.test.ts, .commitmsg, TODO.md C165, root version 1.2.311. Then rebuil
40
40
  ## Follow-up 2026-09-09 evening
41
41
  - Button beside the chip ("Trust the ‹List-Id› list"), From-menu item now toggles (Stop trusting…), docs reworded re editing allowlist.jsonc. Danger banners keep no list button: 123/123 proved-list danger cases in 120 days were URL phish/malware listings.
42
42
 
43
+ ## Self-spoof false positive (found from Bob's screenshot, 2026-09-09 late)
44
+ - ISOC + berglist posts red as "claims to be from your own address": Delivered-To = list address = From, and selfSpoof took ANY dkim=fail in ANY Authentication-Results as proof of forgery. v1.2.314: DMARC-aligned pass vetoes. Next (v1.2.315): alignedPass() — From domain's own SPF pass or DKIM pass vetoes (relaxed alignment for domains with no DMARC policy). Store: 35 → 20 → 15 findings; the 15 are real phish.
45
+ - Danger banner on a proved-list post now names the list and says right-click From / that trust would not clear it.
46
+
43
47
  ## Status
44
48
  - [x] trust.ts
45
49
  - [x] settings/store/service/web
46
50
  - [x] client (banner button, From-menu item, chip tooltip)
47
51
  - [x] tests pass (tests/trust.test.ts 40/40)
48
52
  - [x] docs/TODO/.commitmsg/versions (v1.2.312)
49
- - [x] rebuild.cmd — published v1.2.312 + APK built (exit 0). App must be restarted to pick up the new bundle.
53
+ - [x] rebuild.cmd — v1.2.312 (feature) + v1.2.313 (chip button + undo toggle) published, APKs built. Restart the app to pick up.
@@ -2267,6 +2267,23 @@ function dkimSigners(input) {
2267
2267
  }
2268
2268
  return out;
2269
2269
  }
2270
+ function alignedPass(input) {
2271
+ const fromDomain = (bare(input.fromAddress).split("@")[1] || "").toLowerCase();
2272
+ if (!fromDomain)
2273
+ return "";
2274
+ if (dkimSigners(input).some((d) => sameOrg(d, fromDomain)))
2275
+ return "dkim";
2276
+ const auth = headerAll(input.headerLines, "authentication-results")[0] || "";
2277
+ for (const part of auth.split(";")) {
2278
+ if (!/\bspf=pass\b/i.test(part))
2279
+ continue;
2280
+ const mailfrom = (part.match(/(?:spf|smtp)\.mailfrom=([^\s;,]+)/i)?.[1] || "").toLowerCase();
2281
+ const domain = mailfrom.includes("@") ? mailfrom.split("@")[1] : mailfrom;
2282
+ if (domain && sameOrg(domain, fromDomain))
2283
+ return "spf";
2284
+ }
2285
+ return "";
2286
+ }
2270
2287
  function provedIntermediary(input) {
2271
2288
  const list = (input.trustedIntermediaries || []).map((d) => (d || "").trim().toLowerCase()).filter(Boolean);
2272
2289
  if (!list.length)
@@ -2483,6 +2500,8 @@ function selfSpoof(input) {
2483
2500
  const auth = headerAll(input.headerLines, "authentication-results").join(" ; ");
2484
2501
  if (!auth)
2485
2502
  return null;
2503
+ if (dmarcProof(input).pass || alignedPass(input))
2504
+ return null;
2486
2505
  const failed = [
2487
2506
  /\bspf=(fail|softfail)\b/i.test(auth) ? "SPF" : "",
2488
2507
  /\bdkim=(fail|permerror)\b/i.test(auth) ? "DKIM" : "",