Compare commits

..

74 Commits

Author SHA1 Message Date
ce17c4a7d8 chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 54s
Continuous integration / Test Suite (push) Successful in 1m24s
Continuous integration / Trunk (push) Successful in 58s
Continuous integration / Rustfmt (push) Successful in 41s
Continuous integration / build (push) Successful in 1m22s
Continuous integration / Disallow unused dependencies (push) Successful in 2m12s
2025-08-11 14:54:16 -07:00
c8850404b8 server: rework dmarc parsing to use askama 2025-08-11 14:53:12 -07:00
638e94b4ae web: create seperate email overrides CSS file 2025-08-11 12:42:45 -07:00
d0f4716d83 server: add gzip dmarc email support
Some checks failed
Continuous integration / Check (push) Failing after 59s
Continuous integration / Test Suite (push) Failing after 1m32s
Continuous integration / Trunk (push) Failing after 47s
Continuous integration / Rustfmt (push) Failing after 35s
Continuous integration / build (push) Failing after 1m39s
Continuous integration / Disallow unused dependencies (push) Failing after 2m5s
2025-08-11 12:41:25 -07:00
59e35062e7 server: handle application/zip for google dmarc 2025-08-11 12:41:03 -07:00
43827b4d87 Merge pull request 'fix(deps): update rust crate uuid to v1.18.0' (#145) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 54s
Continuous integration / Test Suite (push) Successful in 1m2s
Continuous integration / Trunk (push) Successful in 56s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 1m21s
Continuous integration / Disallow unused dependencies (push) Successful in 2m3s
2025-08-11 03:45:52 -07:00
b29e92cd9c fix(deps): update rust crate uuid to v1.18.0
All checks were successful
Continuous integration / Check (push) Successful in 56s
Continuous integration / Test Suite (push) Successful in 1m4s
Continuous integration / Trunk (push) Successful in 54s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 1m23s
Continuous integration / Disallow unused dependencies (push) Successful in 2m4s
2025-08-11 10:31:27 +00:00
42bea43de9 Merge pull request 'chore(deps): lock file maintenance' (#144) from renovate/lock-file-maintenance into master
All checks were successful
Continuous integration / Check (push) Successful in 54s
Continuous integration / Test Suite (push) Successful in 1m1s
Continuous integration / Trunk (push) Successful in 7m34s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 1m19s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-08-10 18:01:35 -07:00
4048edde11 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 2m9s
Continuous integration / Test Suite (push) Successful in 4m15s
Continuous integration / Trunk (push) Successful in 7m9s
Continuous integration / Rustfmt (push) Successful in 44s
Continuous integration / build (push) Successful in 4m30s
Continuous integration / Disallow unused dependencies (push) Successful in 2m7s
2025-08-11 00:01:53 +00:00
90768d0d1b Merge pull request 'fix(deps): update rust crate clap to v4.5.43' (#143) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m4s
Continuous integration / Test Suite (push) Successful in 2m18s
Continuous integration / Trunk (push) Successful in 1m3s
Continuous integration / Rustfmt (push) Successful in 51s
Continuous integration / build (push) Successful in 2m10s
Continuous integration / Disallow unused dependencies (push) Successful in 2m3s
2025-08-06 10:15:44 -07:00
70e6271ca3 fix(deps): update rust crate clap to v4.5.43
All checks were successful
Continuous integration / Check (push) Successful in 1m30s
Continuous integration / Test Suite (push) Successful in 1m49s
Continuous integration / Trunk (push) Successful in 7m31s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 3m21s
Continuous integration / Disallow unused dependencies (push) Successful in 2m14s
2025-08-06 16:46:18 +00:00
0bda21e5e9 Merge pull request 'chore(deps): lock file maintenance' (#142) from renovate/lock-file-maintenance into master
All checks were successful
Continuous integration / Check (push) Successful in 1m26s
Continuous integration / Test Suite (push) Successful in 1m57s
Continuous integration / Trunk (push) Successful in 7m55s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 2m17s
Continuous integration / Disallow unused dependencies (push) Successful in 2m14s
2025-08-03 18:01:42 -07:00
f987b4e4b4 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 1m33s
Continuous integration / Test Suite (push) Successful in 3m31s
Continuous integration / Trunk (push) Successful in 7m29s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 3m25s
Continuous integration / Disallow unused dependencies (push) Successful in 2m16s
2025-08-04 00:01:42 +00:00
a873ec9208 Merge pull request 'fix(deps): update rust crate tokio to v1.47.1' (#141) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m29s
Continuous integration / Test Suite (push) Successful in 2m22s
Continuous integration / Trunk (push) Successful in 1m18s
Continuous integration / Rustfmt (push) Successful in 55s
Continuous integration / build (push) Successful in 2m2s
Continuous integration / Disallow unused dependencies (push) Successful in 2m15s
2025-08-01 05:16:00 -07:00
d8d26e1f59 fix(deps): update rust crate tokio to v1.47.1
All checks were successful
Continuous integration / Check (push) Successful in 1m17s
Continuous integration / Test Suite (push) Successful in 2m34s
Continuous integration / Trunk (push) Successful in 7m13s
Continuous integration / Rustfmt (push) Successful in 42s
Continuous integration / build (push) Successful in 2m40s
Continuous integration / Disallow unused dependencies (push) Successful in 2m18s
2025-08-01 11:46:16 +00:00
1322dde5c5 Merge pull request 'fix(deps): update rust crate serde_json to v1.0.142' (#140) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m6s
Continuous integration / Test Suite (push) Successful in 3m3s
Continuous integration / Trunk (push) Successful in 55s
Continuous integration / Rustfmt (push) Successful in 41s
Continuous integration / build (push) Successful in 2m12s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-07-31 17:45:58 -07:00
a2147081e8 fix(deps): update rust crate serde_json to v1.0.142
All checks were successful
Continuous integration / Check (push) Successful in 1m14s
Continuous integration / Test Suite (push) Successful in 2m26s
Continuous integration / Trunk (push) Successful in 7m15s
Continuous integration / Rustfmt (push) Successful in 45s
Continuous integration / build (push) Successful in 3m34s
Continuous integration / Disallow unused dependencies (push) Successful in 2m3s
2025-08-01 00:01:45 +00:00
8c6a24e400 Merge pull request 'fix(deps): update rust crate clap to v4.5.42' (#139) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m7s
Continuous integration / Test Suite (push) Successful in 1m55s
Continuous integration / Trunk (push) Successful in 53s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 1m58s
Continuous integration / Disallow unused dependencies (push) Successful in 2m4s
2025-07-29 20:30:48 -07:00
8a08d97930 fix(deps): update rust crate clap to v4.5.42
All checks were successful
Continuous integration / Check (push) Successful in 1m6s
Continuous integration / Test Suite (push) Successful in 1m39s
Continuous integration / Trunk (push) Successful in 7m17s
Continuous integration / Rustfmt (push) Successful in 46s
Continuous integration / build (push) Successful in 2m1s
Continuous integration / Disallow unused dependencies (push) Successful in 2m12s
2025-07-30 03:01:20 +00:00
d24a851cd7 Merge pull request 'chore(deps): lock file maintenance' (#138) from renovate/lock-file-maintenance into master
All checks were successful
Continuous integration / Check (push) Successful in 1m27s
Continuous integration / Test Suite (push) Successful in 2m8s
Continuous integration / Trunk (push) Successful in 7m13s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 2m23s
Continuous integration / Disallow unused dependencies (push) Successful in 2m38s
2025-07-27 17:31:34 -07:00
f6ff597f66 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 1m1s
Continuous integration / Test Suite (push) Successful in 3m28s
Continuous integration / Trunk (push) Successful in 7m21s
Continuous integration / Rustfmt (push) Successful in 45s
Continuous integration / build (push) Successful in 2m29s
Continuous integration / Disallow unused dependencies (push) Successful in 2m14s
2025-07-28 00:01:34 +00:00
387d133f09 Merge pull request 'fix(deps): update rust crate css-inline to 0.17.0' (#137) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m0s
Continuous integration / Test Suite (push) Successful in 1m31s
Continuous integration / Trunk (push) Successful in 1m23s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 1m56s
Continuous integration / Disallow unused dependencies (push) Successful in 2m17s
2025-07-26 13:15:52 -07:00
a9674e8b7b fix(deps): update rust crate css-inline to 0.17.0
All checks were successful
Continuous integration / Check (push) Successful in 58s
Continuous integration / Test Suite (push) Successful in 1m26s
Continuous integration / Trunk (push) Successful in 1m10s
Continuous integration / Rustfmt (push) Successful in 45s
Continuous integration / build (push) Successful in 2m58s
Continuous integration / Disallow unused dependencies (push) Successful in 2m8s
2025-07-26 20:01:22 +00:00
457f9ac1c2 Merge pull request 'fix(deps): update rust crate tokio to v1.47.0' (#136) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m43s
Continuous integration / Test Suite (push) Successful in 1m35s
Continuous integration / Trunk (push) Successful in 1m0s
Continuous integration / Rustfmt (push) Successful in 1m8s
Continuous integration / build (push) Successful in 2m36s
Continuous integration / Disallow unused dependencies (push) Successful in 2m21s
2025-07-26 09:31:17 -07:00
d62759565f fix(deps): update rust crate tokio to v1.47.0
All checks were successful
Continuous integration / Check (push) Successful in 1m11s
Continuous integration / Test Suite (push) Successful in 2m48s
Continuous integration / Trunk (push) Successful in 7m20s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 2m46s
Continuous integration / Disallow unused dependencies (push) Successful in 2m13s
2025-07-26 15:32:00 +00:00
4fd97700f7 Merge pull request 'chore(deps): lock file maintenance' (#134) from renovate/lock-file-maintenance into master
All checks were successful
Continuous integration / Check (push) Successful in 1m31s
Continuous integration / Test Suite (push) Successful in 2m15s
Continuous integration / Trunk (push) Successful in 7m55s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 2m27s
Continuous integration / Disallow unused dependencies (push) Successful in 2m9s
2025-07-20 17:31:41 -07:00
99b9a88663 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 1m24s
Continuous integration / Test Suite (push) Successful in 2m26s
Continuous integration / Trunk (push) Successful in 1m4s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 3m2s
Continuous integration / Disallow unused dependencies (push) Successful in 2m3s
2025-07-21 00:01:49 +00:00
56e6036892 Merge pull request 'fix(deps): update rust crate strum_macros to v0.27.2' (#133) from renovate/strum-monorepo into master
All checks were successful
Continuous integration / Check (push) Successful in 57s
Continuous integration / Test Suite (push) Successful in 1m14s
Continuous integration / Trunk (push) Successful in 51s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 1m39s
Continuous integration / Disallow unused dependencies (push) Successful in 2m7s
2025-07-20 10:45:48 -07:00
232e436378 fix(deps): update rust crate strum_macros to v0.27.2
All checks were successful
Continuous integration / Check (push) Successful in 57s
Continuous integration / Test Suite (push) Successful in 1m28s
Continuous integration / Trunk (push) Successful in 51s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 1m49s
Continuous integration / Disallow unused dependencies (push) Successful in 2m4s
2025-07-20 16:46:45 +00:00
e2bf4d890f chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 1m5s
Continuous integration / Test Suite (push) Successful in 1m24s
Continuous integration / Trunk (push) Successful in 59s
Continuous integration / Rustfmt (push) Successful in 41s
Continuous integration / build (push) Successful in 1m37s
Continuous integration / Disallow unused dependencies (push) Successful in 2m3s
2025-07-20 09:32:44 -07:00
e9584785a8 web: address -D warning error 2025-07-20 09:32:22 -07:00
7a4d2abdd5 Merge branch 'renovate/all-minor-patch'
Some checks failed
Continuous integration / Check (push) Successful in 54s
Continuous integration / Test Suite (push) Successful in 1m40s
Continuous integration / Trunk (push) Failing after 46s
Continuous integration / Rustfmt (push) Successful in 41s
Continuous integration / build (push) Successful in 1m39s
Continuous integration / Disallow unused dependencies (push) Successful in 2m4s
2025-07-18 16:07:20 -07:00
b764d725b1 fix(deps): update all non-major dependencies
Some checks failed
Continuous integration / Check (push) Successful in 1m18s
Continuous integration / Test Suite (push) Successful in 1m59s
Continuous integration / Trunk (push) Failing after 58s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 3m24s
Continuous integration / Disallow unused dependencies (push) Successful in 2m5s
2025-07-18 19:01:31 +00:00
7bac98762c Merge pull request 'chore(deps): lock file maintenance' (#131) from renovate/lock-file-maintenance into master
Some checks failed
Continuous integration / Check (push) Successful in 1m41s
Continuous integration / Test Suite (push) Successful in 3m3s
Continuous integration / Trunk (push) Failing after 7m47s
Continuous integration / Rustfmt (push) Successful in 52s
Continuous integration / build (push) Successful in 1m59s
Continuous integration / Disallow unused dependencies (push) Successful in 2m15s
2025-07-13 17:46:50 -07:00
2bedd92e1a chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 1m31s
Continuous integration / Test Suite (push) Successful in 2m25s
Continuous integration / Trunk (push) Successful in 7m43s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 2m22s
Continuous integration / Disallow unused dependencies (push) Successful in 2m21s
2025-07-14 00:01:43 +00:00
da72c09fa3 Merge pull request 'fix(deps): update rust crate clap to v4.5.41' (#130) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 55s
Continuous integration / Test Suite (push) Successful in 1m59s
Continuous integration / Trunk (push) Successful in 58s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 1m57s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-07-09 16:00:58 -07:00
38c1942ebb fix(deps): update rust crate clap to v4.5.41
All checks were successful
Continuous integration / Check (push) Successful in 58s
Continuous integration / Test Suite (push) Successful in 1m33s
Continuous integration / Trunk (push) Successful in 7m15s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 1m41s
Continuous integration / Disallow unused dependencies (push) Successful in 2m5s
2025-07-09 22:46:22 +00:00
05a7386dd1 Merge pull request 'fix(deps): update rust crate ammonia to v4.1.1' (#129) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 47s
Continuous integration / Test Suite (push) Successful in 1m16s
Continuous integration / Trunk (push) Successful in 47s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 1m32s
Continuous integration / Disallow unused dependencies (push) Successful in 2m4s
2025-07-08 10:00:50 -07:00
477ffe8d82 fix(deps): update rust crate ammonia to v4.1.1
All checks were successful
Continuous integration / Check (push) Successful in 52s
Continuous integration / Test Suite (push) Successful in 1m43s
Continuous integration / Trunk (push) Successful in 7m20s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 2m57s
Continuous integration / Disallow unused dependencies (push) Successful in 2m11s
2025-07-08 16:31:39 +00:00
5d80f32b49 Merge pull request 'chore(deps): lock file maintenance' (#128) from renovate/lock-file-maintenance into master
All checks were successful
Continuous integration / Check (push) Successful in 1m44s
Continuous integration / Test Suite (push) Successful in 2m53s
Continuous integration / Trunk (push) Successful in 7m38s
Continuous integration / Rustfmt (push) Successful in 35s
Continuous integration / build (push) Successful in 2m24s
Continuous integration / Disallow unused dependencies (push) Successful in 2m30s
2025-07-06 17:46:42 -07:00
ae76bdf9a5 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 1m16s
Continuous integration / Test Suite (push) Successful in 2m5s
Continuous integration / Trunk (push) Successful in 7m15s
Continuous integration / Rustfmt (push) Successful in 45s
Continuous integration / build (push) Successful in 2m24s
Continuous integration / Disallow unused dependencies (push) Successful in 2m9s
2025-07-07 00:01:43 +00:00
50e3c77e49 Merge pull request 'fix(deps): update rust crate tokio to v1.46.1' (#127) from renovate/all-minor-patch into master
All checks were successful
Continuous integration / Check (push) Successful in 1m21s
Continuous integration / Test Suite (push) Successful in 1m27s
Continuous integration / Trunk (push) Successful in 1m10s
Continuous integration / Rustfmt (push) Successful in 56s
Continuous integration / build (push) Successful in 1m32s
Continuous integration / Disallow unused dependencies (push) Successful in 2m59s
2025-07-04 14:01:06 -07:00
e85a505775 fix(deps): update rust crate tokio to v1.46.1
All checks were successful
Continuous integration / Check (push) Successful in 1m4s
Continuous integration / Test Suite (push) Successful in 1m52s
Continuous integration / Trunk (push) Successful in 7m18s
Continuous integration / Rustfmt (push) Successful in 45s
Continuous integration / build (push) Successful in 2m25s
Continuous integration / Disallow unused dependencies (push) Successful in 2m8s
2025-07-04 20:16:47 +00:00
86ea5a13f3 fix(deps): update rust crate tokio to v1.46.0
All checks were successful
Continuous integration / Check (push) Successful in 59s
Continuous integration / Test Suite (push) Successful in 1m16s
Continuous integration / Trunk (push) Successful in 59s
Continuous integration / Rustfmt (push) Successful in 50s
Continuous integration / build (push) Successful in 1m23s
Continuous integration / Disallow unused dependencies (push) Successful in 2m21s
2025-07-02 08:31:20 +00:00
a30bff925f fix(deps): update rust crate reqwest to v0.12.22
All checks were successful
Continuous integration / Check (push) Successful in 43s
Continuous integration / Test Suite (push) Successful in 57s
Continuous integration / Trunk (push) Successful in 53s
Continuous integration / Rustfmt (push) Successful in 35s
Continuous integration / build (push) Successful in 1m19s
Continuous integration / Disallow unused dependencies (push) Successful in 2m8s
2025-07-01 18:31:21 +00:00
6fdfbb1ee2 Merge branch 'renovate/all-minor-patch'
All checks were successful
Continuous integration / Check (push) Successful in 51s
Continuous integration / Test Suite (push) Successful in 1m0s
Continuous integration / Trunk (push) Successful in 1m4s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 1m17s
Continuous integration / Disallow unused dependencies (push) Successful in 2m6s
2025-07-01 11:24:26 -07:00
561316ddd4 web: fix letterbox-shared package reference in Cargo.toml 2025-07-01 11:23:41 -07:00
495e495888 fix(deps): update all non-major dependencies
Some checks failed
renovate/artifacts Artifact file update failure
Continuous integration / Rustfmt (push) Waiting to run
Continuous integration / build (push) Waiting to run
Continuous integration / Disallow unused dependencies (push) Waiting to run
Continuous integration / Check (push) Successful in 51s
Continuous integration / Test Suite (push) Successful in 1m2s
Continuous integration / Trunk (push) Has been cancelled
2025-07-01 15:56:35 +00:00
ddb4c812ce chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 48s
Continuous integration / Test Suite (push) Successful in 1m4s
Continuous integration / Trunk (push) Successful in 7m40s
Continuous integration / Rustfmt (push) Successful in 41s
Continuous integration / build (push) Successful in 1m26s
Continuous integration / Disallow unused dependencies (push) Successful in 2m13s
2025-06-30 00:01:45 +00:00
1aaf914ac5 chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 1m12s
Continuous integration / Test Suite (push) Successful in 2m0s
Continuous integration / Trunk (push) Successful in 1m13s
Continuous integration / Rustfmt (push) Successful in 51s
Continuous integration / build (push) Successful in 3m1s
Continuous integration / Disallow unused dependencies (push) Successful in 2m23s
2025-06-23 13:49:28 -07:00
982b5dae2f server: add disabled column to feed table
All checks were successful
Continuous integration / Check (push) Successful in 45s
Continuous integration / Test Suite (push) Successful in 1m7s
Continuous integration / Trunk (push) Successful in 1m7s
Continuous integration / Rustfmt (push) Successful in 54s
Continuous integration / build (push) Successful in 2m36s
Continuous integration / Disallow unused dependencies (push) Successful in 2m29s
2025-06-23 13:41:11 -07:00
8807c1b1f5 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 1m21s
Continuous integration / Test Suite (push) Successful in 1m32s
Continuous integration / Trunk (push) Successful in 1m19s
Continuous integration / Rustfmt (push) Successful in 1m4s
Continuous integration / build (push) Successful in 2m35s
Continuous integration / Disallow unused dependencies (push) Successful in 2m52s
2025-06-23 19:37:51 +00:00
fa23658ef0 web: remove now obsolete allow directive
All checks were successful
Continuous integration / Check (push) Successful in 1m21s
Continuous integration / Test Suite (push) Successful in 1m31s
Continuous integration / Trunk (push) Successful in 1m20s
Continuous integration / Rustfmt (push) Successful in 1m3s
Continuous integration / build (push) Successful in 3m30s
Continuous integration / Disallow unused dependencies (push) Successful in 2m41s
2025-06-23 12:32:23 -07:00
f175faed98 fix(deps): update rust crate css-inline to v0.14.5
All checks were successful
Continuous integration / Check (push) Successful in 39s
Continuous integration / Test Suite (push) Successful in 1m1s
Continuous integration / Trunk (push) Successful in 38s
Continuous integration / Rustfmt (push) Successful in 33s
Continuous integration / build (push) Successful in 53s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-06-16 21:46:30 +00:00
8971c16117 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 39s
Continuous integration / Test Suite (push) Successful in 50s
Continuous integration / Rustfmt (push) Successful in 31s
Continuous integration / Trunk (push) Successful in 50s
Continuous integration / build (push) Successful in 54s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-06-16 00:01:44 +00:00
fbecf564b5 fix(deps): update rust crate reqwest to v0.12.20
All checks were successful
Continuous integration / Check (push) Successful in 37s
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 37s
Continuous integration / build (push) Successful in 53s
Continuous integration / Disallow unused dependencies (push) Successful in 2m0s
2025-06-10 19:16:14 +00:00
e5643c6fd0 fix(deps): update rust crate clap to v4.5.40
All checks were successful
Continuous integration / Test Suite (push) Successful in 45s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Check (push) Successful in 1m30s
Continuous integration / Rustfmt (push) Successful in 31s
Continuous integration / Disallow unused dependencies (push) Successful in 54s
Continuous integration / build (push) Successful in 1m50s
2025-06-09 18:31:15 +00:00
a8734269f7 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 40s
Continuous integration / Test Suite (push) Successful in 44s
Continuous integration / Rustfmt (push) Successful in 33s
Continuous integration / Trunk (push) Successful in 52s
Continuous integration / build (push) Successful in 51s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-06-09 00:01:43 +00:00
cab4e571f3 fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 37s
Continuous integration / Test Suite (push) Successful in 1m13s
Continuous integration / Trunk (push) Successful in 38s
Continuous integration / Rustfmt (push) Successful in 28s
Continuous integration / build (push) Successful in 52s
Continuous integration / Disallow unused dependencies (push) Successful in 1m57s
2025-06-03 13:16:29 +00:00
4d6c6af7d9 fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 38s
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Trunk (push) Successful in 38s
Continuous integration / Rustfmt (push) Successful in 32s
Continuous integration / Disallow unused dependencies (push) Successful in 55s
Continuous integration / build (push) Successful in 1m44s
2025-06-02 12:47:12 +00:00
cf08831ed1 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 38s
Continuous integration / Trunk (push) Successful in 38s
Continuous integration / Rustfmt (push) Successful in 31s
Continuous integration / build (push) Successful in 50s
Continuous integration / Disallow unused dependencies (push) Successful in 55s
Continuous integration / Test Suite (push) Successful in 3m48s
2025-06-02 03:32:02 +00:00
e1509c5978 fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 1m5s
Continuous integration / Test Suite (push) Successful in 44s
Continuous integration / Rustfmt (push) Successful in 32s
Continuous integration / Trunk (push) Successful in 1m18s
Continuous integration / build (push) Successful in 51s
Continuous integration / Disallow unused dependencies (push) Successful in 2m24s
2025-06-01 20:31:35 -07:00
13db8e6f1f chore(deps): lock file maintenance
All checks were successful
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Check (push) Successful in 1m0s
Continuous integration / Trunk (push) Successful in 38s
Continuous integration / Rustfmt (push) Successful in 48s
Continuous integration / build (push) Successful in 53s
Continuous integration / Disallow unused dependencies (push) Successful in 2m0s
2025-06-02 02:46:35 +00:00
136a837fa4 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 46s
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Rustfmt (push) Successful in 32s
Continuous integration / build (push) Successful in 1m8s
Continuous integration / Disallow unused dependencies (push) Successful in 54s
Continuous integration / Trunk (push) Successful in 7m14s
2025-06-02 00:01:42 +00:00
1ea058c664 fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 40s
Continuous integration / Test Suite (push) Successful in 41s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 49s
Continuous integration / Disallow unused dependencies (push) Successful in 2m0s
2025-05-28 16:16:24 +00:00
f4c11c5b3f fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 40s
Continuous integration / Test Suite (push) Successful in 41s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 53s
Continuous integration / Disallow unused dependencies (push) Successful in 2m1s
2025-05-28 13:01:55 +00:00
8dc8f3a0f8 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 38s
Continuous integration / Test Suite (push) Successful in 41s
Continuous integration / Rustfmt (push) Successful in 40s
Continuous integration / build (push) Successful in 2m56s
Continuous integration / Trunk (push) Successful in 3m43s
Continuous integration / Disallow unused dependencies (push) Successful in 2m2s
2025-05-26 00:01:31 +00:00
7b9450b65b fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 54s
Continuous integration / Test Suite (push) Successful in 1m5s
Continuous integration / Trunk (push) Successful in 50s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 1m23s
Continuous integration / Disallow unused dependencies (push) Successful in 1m51s
2025-05-24 14:47:03 +00:00
b5de0719dd fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Test Suite (push) Successful in 47s
Continuous integration / Check (push) Successful in 58s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 39s
Continuous integration / build (push) Successful in 52s
Continuous integration / Disallow unused dependencies (push) Successful in 2m0s
2025-05-24 02:31:52 +00:00
58da28a19b fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Test Suite (push) Successful in 39s
Continuous integration / Check (push) Successful in 51s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 35s
Continuous integration / build (push) Successful in 47s
Continuous integration / Disallow unused dependencies (push) Successful in 2m1s
2025-05-23 23:31:44 +00:00
75ad27ec2f chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 35s
Continuous integration / Test Suite (push) Successful in 40s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 44s
Continuous integration / build (push) Successful in 48s
Continuous integration / Disallow unused dependencies (push) Successful in 2m5s
2025-05-23 16:22:27 -07:00
f904fa0001 Add slurp and CSS for seiya-me 2025-05-23 16:21:57 -07:00
b94596bf65 fix(deps): update all non-major dependencies
All checks were successful
Continuous integration / Check (push) Successful in 37s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Test Suite (push) Successful in 1m13s
Continuous integration / Rustfmt (push) Successful in 32s
Continuous integration / build (push) Successful in 1m19s
Continuous integration / Disallow unused dependencies (push) Successful in 57s
2025-05-22 15:01:32 +00:00
aa24599921 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 41s
Continuous integration / Test Suite (push) Successful in 40s
Continuous integration / Trunk (push) Successful in 41s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 47s
Continuous integration / Disallow unused dependencies (push) Successful in 2m12s
2025-05-19 00:01:49 +00:00
19 changed files with 1479 additions and 853 deletions

1823
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ authors = ["Bill Thiede <git@xinu.tv>"]
edition = "2021"
license = "UNLICENSED"
publish = ["xinu"]
version = "0.17.24"
version = "0.17.28"
repository = "https://git.z.xinu.tv/wathiede/letterbox"
[profile.dev]

View File

@@ -14,26 +14,29 @@ version.workspace = true
[dependencies]
ammonia = "4.1.0"
anyhow = "1.0.98"
askama = { version = "0.14.0", features = ["derive"] }
async-graphql = { version = "7", features = ["log"] }
async-graphql-axum = "7.0.16"
async-trait = "0.1.88"
axum = { version = "0.8.3", features = ["ws"] }
axum-macros = "0.5.0"
build-info = "0.0.40"
build-info = "0.0.41"
cacher = { version = "0.2.0", registry = "xinu" }
chrono = "0.4.40"
clap = { version = "4.5.37", features = ["derive"] }
css-inline = "0.14.4"
css-inline = "0.17.0"
flate2 = "1.1.2"
futures = "0.3.31"
headers = "0.4.0"
html-escape = "0.2.13"
letterbox-notmuch = { path = "../notmuch", version = "0.17.24", registry = "xinu" }
letterbox-shared = { path = "../shared", version = "0.17.24", registry = "xinu" }
letterbox-notmuch = { path = "../notmuch", version = "0.17.28", registry = "xinu" }
letterbox-shared = { path = "../shared", version = "0.17.28", registry = "xinu" }
linkify = "0.10.0"
lol_html = "2.3.0"
mailparse = "0.16.1"
maplit = "1.0.2"
memmap = "0.7.0"
quick-xml = { version = "0.38.1", features = ["serialize"] }
regex = "1.11.1"
reqwest = { version = "0.12.15", features = ["blocking"] }
scraper = "0.23.1"
@@ -50,9 +53,10 @@ urlencoding = "2.1.3"
#xtracing = { git = "http://git-private.h.xinu.tv/wathiede/xtracing.git" }
#xtracing = { path = "../../xtracing" }
xtracing = { version = "0.3.2", registry = "xinu" }
zip = "4.3.0"
[build-dependencies]
build-info-build = "0.0.40"
build-info-build = "0.0.41"
[features]
#default = [ "tantivy" ]

View File

@@ -2,4 +2,5 @@ fn main() {
// Calling `build_info_build::build_script` collects all data and makes it available to `build_info::build_info!`
// and `build_info::format!` in the main program.
build_info_build::build_script();
println!("cargo:rerun-if-changed=templates");
}

View File

@@ -0,0 +1,2 @@
-- Add down migration script here
ALTER TABLE feed DROP COLUMN IF EXISTS disabled;

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TABLE feed ADD disabled boolean;

View File

@@ -39,4 +39,6 @@ pub enum ServerError {
QueryParseError(#[from] QueryParserError),
#[error("impossible: {0}")]
InfaillibleError(#[from] Infallible),
#[error("askama error: {0}")]
AskamaError(#[from] askama::Error),
}

View File

@@ -352,6 +352,9 @@ fn slurp_contents_selectors() -> HashMap<String, Vec<Selector>> {
"natwelch.com".to_string() => vec![
Selector::parse("article div.prose").unwrap(),
],
"seiya.me".to_string() => vec![
Selector::parse("header + div").unwrap(),
],
"rustacean-station.org".to_string() => vec![
Selector::parse("article").unwrap(),
],

View File

@@ -1,14 +1,19 @@
use std::{
collections::{HashMap, HashSet},
fs::File,
io::Cursor,
};
use askama::Template;
use chrono::{TimeZone, Utc};
use letterbox_notmuch::Notmuch;
use letterbox_shared::{compute_color, Rule};
use mailparse::{parse_content_type, parse_mail, MailHeader, MailHeaderMap, ParsedMail};
use memmap::MmapOptions;
use quick_xml::de::from_str as xml_from_str;
use sqlx::{types::Json, PgPool};
use tracing::{error, info, info_span, instrument, warn};
use zip::ZipArchive;
use crate::{
compute_offset_limit,
@@ -20,6 +25,7 @@ use crate::{
linkify_html, InlineStyle, Query, SanitizeHtml, Transformer,
};
const APPLICATION_ZIP: &'static str = "application/zip";
const IMAGE_JPEG: &'static str = "image/jpeg";
const IMAGE_PJPEG: &'static str = "image/pjpeg";
const IMAGE_PNG: &'static str = "image/png";
@@ -447,6 +453,7 @@ fn extract_body(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, Ser
MULTIPART_MIXED => extract_mixed(m, part_addr),
MULTIPART_ALTERNATIVE => extract_alternative(m, part_addr),
MULTIPART_RELATED => extract_related(m, part_addr),
APPLICATION_ZIP => extract_zip(m),
_ => extract_unhandled(m),
};
if let Err(err) = ret {
@@ -456,6 +463,71 @@ fn extract_body(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, Ser
ret
}
const APPLICATION_GZIP: &'static str = "application/gzip";
fn extract_zip(m: &ParsedMail) -> Result<Body, ServerError> {
if let Ok(zip_bytes) = m.get_body_raw() {
if let Ok(mut archive) = ZipArchive::new(Cursor::new(&zip_bytes)) {
for i in 0..archive.len() {
if let Ok(mut file) = archive.by_index(i) {
let name = file.name().to_lowercase();
// Google DMARC reports are typically named like "google.com!example.com!...xml"
// and may or may not contain "dmarc" in the filename.
if name.ends_with(".xml")
&& (name.contains("dmarc") || name.starts_with("google.com!"))
{
let mut xml = String::new();
use std::io::Read;
if file.read_to_string(&mut xml).is_ok() {
match parse_dmarc_report(&xml) {
Ok(report) => {
return Ok(Body::html(format!(
"<div class=\"dmarc-report\">Google DMARC report summary:<br>{}</div>",
report
)));
}
Err(e) => {
return Ok(Body::html(format!(
"<div class=\"dmarc-report-error\">Failed to parse DMARC report XML: {}</div>",
e
)));
}
}
}
}
}
}
}
}
// If no DMARC report found, fall through to unhandled
extract_unhandled(m)
}
fn extract_gzip(m: &ParsedMail) -> Result<Body, ServerError> {
if let Ok(gz_bytes) = m.get_body_raw() {
let mut decoder = flate2::read::GzDecoder::new(&gz_bytes[..]);
let mut xml = String::new();
use std::io::Read;
if decoder.read_to_string(&mut xml).is_ok() {
match parse_dmarc_report(&xml) {
Ok(report) => {
return Ok(Body::html(format!(
"<div class=\"dmarc-report\">Microsoft DMARC report summary:<br>{}</div>",
report
)));
}
Err(e) => {
return Ok(Body::html(format!(
"<div class=\"dmarc-report-error\">Failed to parse DMARC report XML: {}</div>",
e
)));
}
}
}
}
extract_unhandled(m)
}
fn extract_unhandled(m: &ParsedMail) -> Result<Body, ServerError> {
let msg = format!(
"Unhandled body content type:\n{}\n{}",
@@ -525,6 +597,7 @@ fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, Se
MULTIPART_RELATED,
TEXT_HTML,
TEXT_PLAIN,
APPLICATION_GZIP,
];
let mut unhandled_types: Vec<_> = m
.subparts
@@ -568,6 +641,7 @@ fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, Se
)));
}
}
APPLICATION_GZIP => parts.push(extract_gzip(sp)?),
mt => parts.push(unhandled_html(MULTIPART_MIXED, mt)),
}
part_addr.pop();
@@ -1103,3 +1177,267 @@ fn find_tags<'a, 'b>(rules: &'a [Rule], headers: &'b [MailHeader]) -> (bool, Has
}
return (matched_rule, add_tags);
}
// Add this helper function to parse the DMARC XML and summarize it.
#[derive(Debug, serde::Deserialize)]
pub struct FormattedDateRange {
pub begin: String,
pub end: String,
}
pub struct FormattedReportMetadata {
pub org_name: String,
pub email: String,
pub report_id: String,
pub date_range: Option<FormattedDateRange>,
}
pub struct FormattedRecord {
pub source_ip: String,
pub count: String,
pub header_from: String,
pub disposition: String,
pub dkim: String,
pub spf: String,
pub auth_results: Option<FormattedAuthResults>,
}
pub struct FormattedAuthResults {
pub dkim: Vec<FormattedAuthDKIM>,
pub spf: Vec<FormattedAuthSPF>,
}
pub struct FormattedAuthDKIM {
pub domain: String,
pub result: String,
pub selector: String,
}
pub struct FormattedAuthSPF {
pub domain: String,
pub result: String,
pub scope: String,
}
pub struct FormattedPolicyPublished {
pub domain: String,
pub adkim: String,
pub aspf: String,
pub p: String,
pub sp: String,
pub pct: String,
}
pub struct FormattedFeedback {
pub report_metadata: Option<FormattedReportMetadata>,
pub policy_published: Option<FormattedPolicyPublished>,
pub record: Option<Vec<FormattedRecord>>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Feedback {
pub report_metadata: Option<ReportMetadata>,
pub policy_published: Option<PolicyPublished>,
pub record: Option<Vec<Record>>,
}
#[derive(Debug, serde::Deserialize)]
pub struct ReportMetadata {
pub org_name: Option<String>,
pub email: Option<String>,
pub report_id: Option<String>,
pub date_range: Option<DateRange>,
}
#[derive(Debug, serde::Deserialize)]
pub struct DateRange {
pub begin: Option<u64>,
pub end: Option<u64>,
}
#[derive(Debug, serde::Deserialize)]
pub struct PolicyPublished {
pub domain: Option<String>,
pub adkim: Option<String>,
pub aspf: Option<String>,
pub p: Option<String>,
pub sp: Option<String>,
pub pct: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Record {
pub row: Option<Row>,
pub identifiers: Option<Identifiers>,
pub auth_results: Option<AuthResults>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Row {
pub source_ip: Option<String>,
pub count: Option<u64>,
pub policy_evaluated: Option<PolicyEvaluated>,
}
#[derive(Debug, serde::Deserialize)]
pub struct PolicyEvaluated {
pub disposition: Option<String>,
pub dkim: Option<String>,
pub spf: Option<String>,
pub reason: Option<Vec<Reason>>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Reason {
#[serde(rename = "type")]
pub reason_type: Option<String>,
pub comment: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
pub struct Identifiers {
pub header_from: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
pub struct AuthResults {
pub dkim: Option<Vec<AuthDKIM>>,
pub spf: Option<Vec<AuthSPF>>,
}
#[derive(Debug, serde::Deserialize)]
pub struct AuthDKIM {
pub domain: Option<String>,
pub result: Option<String>,
pub selector: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
pub struct AuthSPF {
pub domain: Option<String>,
pub result: Option<String>,
pub scope: Option<String>,
}
#[derive(Template)]
#[template(path = "dmarc_report.html")]
pub struct DmarcReportTemplate<'a> {
pub report: &'a FormattedFeedback,
}
// Add this helper function to parse the DMARC XML and summarize it.
pub fn parse_dmarc_report(xml: &str) -> Result<String, ServerError> {
let feedback: Feedback = xml_from_str(xml)
.map_err(|e| ServerError::StringError(format!("DMARC XML parse error: {}", e)))?;
let formatted_report_metadata = feedback.report_metadata.map(|meta| {
let date_range = meta.date_range.map(|dr| FormattedDateRange {
begin: match Utc.timestamp_opt(dr.begin.unwrap_or(0) as i64, 0) {
chrono::LocalResult::Single(d) => Some(d),
_ => None,
}
.map(|d| d.format("%Y-%m-%d").to_string())
.unwrap_or_else(|| "".to_string()),
end: match Utc.timestamp_opt(dr.end.unwrap_or(0) as i64, 0) {
chrono::LocalResult::Single(d) => Some(d),
_ => None,
}
.map(|d| d.format("%Y-%m-%d").to_string())
.unwrap_or_else(|| "".to_string()),
});
FormattedReportMetadata {
org_name: meta.org_name.unwrap_or_else(|| "".to_string()),
email: meta.email.unwrap_or_else(|| "".to_string()),
report_id: meta.report_id.unwrap_or_else(|| "".to_string()),
date_range,
}
});
let formatted_record = feedback.record.map(|records| {
records
.into_iter()
.map(|rec| {
let auth_results = rec.auth_results.map(|auth| {
let dkim = auth
.dkim
.map(|dkims| {
dkims
.into_iter()
.map(|d| FormattedAuthDKIM {
domain: d.domain.unwrap_or_else(|| "".to_string()),
result: d.result.unwrap_or_else(|| "".to_string()),
selector: d.selector.unwrap_or_else(|| "".to_string()),
})
.collect()
})
.unwrap_or_else(|| Vec::new());
let spf = auth
.spf
.map(|spfs| {
spfs.into_iter()
.map(|s| FormattedAuthSPF {
domain: s.domain.unwrap_or_else(|| "".to_string()),
result: s.result.unwrap_or_else(|| "".to_string()),
scope: s.scope.unwrap_or_else(|| "".to_string()),
})
.collect()
})
.unwrap_or_else(|| Vec::new());
FormattedAuthResults { dkim, spf }
});
FormattedRecord {
source_ip: rec
.row
.as_ref()
.and_then(|r| r.source_ip.clone())
.unwrap_or_else(|| "".to_string()),
count: rec
.row
.as_ref()
.and_then(|r| r.count.map(|c| c.to_string()))
.unwrap_or_else(|| "".to_string()),
header_from: rec
.identifiers
.as_ref()
.and_then(|i| i.header_from.clone())
.unwrap_or_else(|| "".to_string()),
disposition: rec
.row
.as_ref()
.and_then(|r| r.policy_evaluated.as_ref())
.and_then(|p| p.disposition.clone())
.unwrap_or_else(|| "".to_string()),
dkim: rec
.row
.as_ref()
.and_then(|r| r.policy_evaluated.as_ref())
.and_then(|p| p.dkim.clone())
.unwrap_or_else(|| "".to_string()),
spf: rec
.row
.as_ref()
.and_then(|r| r.policy_evaluated.as_ref())
.and_then(|p| p.spf.clone())
.unwrap_or_else(|| "".to_string()),
auth_results,
}
})
.collect()
});
let formatted_policy_published =
feedback
.policy_published
.map(|pol| FormattedPolicyPublished {
domain: pol.domain.unwrap_or_else(|| "".to_string()),
adkim: pol.adkim.unwrap_or_else(|| "".to_string()),
aspf: pol.aspf.unwrap_or_else(|| "".to_string()),
p: pol.p.unwrap_or_else(|| "".to_string()),
sp: pol.sp.unwrap_or_else(|| "".to_string()),
pct: pol.pct.unwrap_or_else(|| "".to_string()),
});
let formatted_feedback = FormattedFeedback {
report_metadata: formatted_report_metadata,
policy_published: formatted_policy_published,
record: formatted_record,
};
let template = DmarcReportTemplate {
report: &formatted_feedback,
};
let html = template.render()?;
Ok(html)
}

7
server/src/templates.rs Normal file
View File

@@ -0,0 +1,7 @@
use askama::Template;
#[derive(Template)]
#[template(path = "dmarc_report.html")]
pub struct DmarcReportTemplate<'a> {
pub feedback: &'a crate::nm::Feedback,
}

View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<title>DMARC Report</title>
</head>
<body>
{% if report.report_metadata.is_some() %}
{% let meta = report.report_metadata.as_ref().unwrap() %}
<b>Reporter:</b> {{ meta.org_name }}<br>
<b>Contact:</b> {{ meta.email }}<br>
<b>Report ID:</b> {{ meta.report_id }}<br>
{% if meta.date_range.is_some() %}
{% let dr = meta.date_range.as_ref().unwrap() %}
<b>Date range:</b>
{{ dr.begin }}
to
{{ dr.end }}
<br>
{% endif %}
{% endif %}
{% if report.policy_published.is_some() %}
{% let pol = report.policy_published.as_ref().unwrap() %}
<b>Policy Published:</b>
<ul>
<li>Domain: {{ pol.domain }}</li>
<li>ADKIM: {{ pol.adkim }}</li>
<li>ASPF: {{ pol.aspf }}</li>
<li>Policy: {{ pol.p }}</li>
<li>Subdomain Policy: {{ pol.sp }}</li>
<li>Percent: {{ pol.pct }}</li>
</ul>
{% endif %}
{% if report.record.is_some() %}
<b>Records:</b>
<table style="border-collapse:collapse;width:100%;font-size:0.95em;">
<thead>
<tr style="background:#f0f0f0;">
<th style="border:1px solid #bbb;padding:4px 8px;">Source IP</th>
<th style="border:1px solid #bbb;padding:4px 8px;">Count</th>
<th style="border:1px solid #bbb;padding:4px 8px;">Header From</th>
<th style="border:1px solid #bbb;padding:4px 8px;">Disposition</th>
<th style="border:1px solid #bbb;padding:4px 8px;">DKIM</th>
<th style="border:1px solid #bbb;padding:4px 8px;">SPF</th>
<th style="border:1px solid #bbb;padding:4px 8px;">Auth Results</th>
</tr>
</thead>
<tbody>
{% for rec in report.record.as_ref().unwrap() %}
<tr>
<td style="border:1px solid #bbb;padding:4px 8px;">{{ rec.source_ip }}</td>
<td style="border:1px solid #bbb;padding:4px 8px;">{{ rec.count }}</td>
<td style="border:1px solid #bbb;padding:4px 8px;">{{ rec.header_from }}</td>
<td style="border:1px solid #bbb;padding:4px 8px;">{{ rec.disposition }}</td>
<td style="border:1px solid #bbb;padding:4px 8px;">{{ rec.dkim }}</td>
<td style="border:1px solid #bbb;padding:4px 8px;">{{ rec.spf }}</td>
<td style="border:1px solid #bbb;padding:4px 8px;">
{% if rec.auth_results.is_some() %}
{% let auth = rec.auth_results.as_ref().unwrap() %}
{% for dkimres in auth.dkim %}
<span style="white-space:nowrap;">
DKIM: domain=<b>{{ dkimres.domain }}</b>
selector=<b>{{ dkimres.selector }}</b>
result=<b>{{ dkimres.result }}</b>
</span><br>
{% endfor %}
{% for spfres in auth.spf %}
<span style="white-space:nowrap;">
SPF: domain=<b>{{ spfres.domain }}</b>
scope=<b>{{ spfres.scope }}</b>
result=<b>{{ spfres.result }}</b>
</span><br>
{% endfor %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if report.report_metadata.is_none() && report.policy_published.is_none() && report.record.is_none() %}
<p>No DMARC summary found.</p>
{% endif %}
</body>
</html>

View File

@@ -11,8 +11,8 @@ version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
build-info = "0.0.40"
letterbox-notmuch = { path = "../notmuch", version = "0.17.24", registry = "xinu" }
build-info = "0.0.41"
letterbox-notmuch = { path = "../notmuch", version = "0.17.28", registry = "xinu" }
regex = "1.11.1"
serde = { version = "1.0.219", features = ["derive"] }
sqlx = "0.8.5"

View File

@@ -9,7 +9,7 @@ repository.workspace = true
version.workspace = true
[build-dependencies]
build-info-build = "0.0.40"
build-info-build = "0.0.41"
[dev-dependencies]
wasm-bindgen-test = "0.3.50"
@@ -28,12 +28,12 @@ graphql_client = "0.14.0"
thiserror = "2.0.12"
gloo-net = { version = "0.6.0", features = ["json", "serde_json"] }
human_format = "1.1.0"
build-info = "0.0.40"
build-info = "0.0.41"
wasm-bindgen = "=0.2.100"
uuid = { version = "1.16.0", features = [
"js",
] } # direct dep to set js feature, prevents Rng issues
letterbox-shared = { version = "0.17.9", registry = "xinu" }
letterbox-shared = { path = "../shared/", version = "0.17.28", registry = "xinu" }
seed_hooks = { version = "0.4.1", registry = "xinu" }
strum_macros = "0.27.1"
gloo-console = "0.3.0"

View File

@@ -16,10 +16,11 @@
<link data-trunk rel="css" href="static/vars.css" />
<link data-trunk rel="tailwind-css" href="./src/tailwind.css" />
<link data-trunk rel="css" href="static/overrides.css" />
<link data-trunk rel="css" href="static/email-specific.css" />
</head>
<body>
<section id="app"></section>
</body>
</html>
</html>

View File

@@ -2,8 +2,6 @@
// - it's useful when you want to check your code with `cargo make verify`
// but some rules are too "annoying" or are not applicable for your case.)
#![allow(clippy::wildcard_imports)]
// Until https://github.com/rust-lang/rust/issues/138762 is addressed in dependencies
#![allow(wasm_c_abi)]
use log::Level;
use seed::App;

View File

@@ -1025,7 +1025,7 @@ fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool)
],
IF!(open =>
div![
C!["content", "bg-white", "text-black", "p-4", "min-w-full", "w-0","overflow-x-auto", from],
C!["content", "bg-white", "text-black", "p-4", "min-w-full", "w-0","overflow-x-auto", from.map(|f|format!("from-{f}"))],
match &msg.body {
ShowThreadQueryThreadOnEmailThreadMessagesBody::UnhandledContentType(
ShowThreadQueryThreadOnEmailThreadMessagesBodyOnUnhandledContentType { contents ,content_tree},

View File

@@ -63,13 +63,6 @@ use wasm_sockets::{ConnectionStatus, EventClient, Message, WebSocketError};
use wasm_sockets::{ConnectionStatus, EventClient, Message, WebSocketError};
use web_sys::CloseEvent;
/// Message from the server to the client.
#[derive(Serialize, Deserialize)]
pub struct ServerMessage {
pub id: usize,
pub text: String,
}
/// Message from the client to the server.
#[derive(Serialize, Deserialize)]
pub struct ClientMessage {

View File

@@ -0,0 +1,11 @@
.mail-thread .content.from-noreply-news-bloomberg-com a {
background-color: initial !important;
}
.mail-thread .content.from-noreply-news-bloomberg-com h2 {
margin: 0 !important;
padding: 0 !important;
}
.mail-thread .content.from-dmarcreport-microsoft-com div {
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !important;
}

View File

@@ -57,15 +57,6 @@ html {
margin-left: 2em;
}
.mail-thread .content .noreply-news-bloomberg-com a {
background-color: initial !important;
}
.mail-thread .content .noreply-news-bloomberg-com h2 {
margin: 0 !important;
padding: 0 !important;
}
/* Hackaday figures have unreadable black on dark grey */
.news-post figcaption.wp-caption-text {
background-color: initial !important;
@@ -76,6 +67,11 @@ html {
display: none !important;
}
.news-post.site-seiya-me figure>pre,
.news-post.site-seiya-me figure>pre>code {
background-color: black !important;
}
.news-post.site-slashdot .story-byline {
display: block !important;
height: initial !important;