Compare commits

...
1 Commits
Author SHA1 Message Date
Bendik LynghaugandClaude Opus 5 5b381e4f60 Type a payload's PayloadVersion as an integer
docs / deploy (push) Successful in 3s
Test / test (push) Successful in 2m11s
Publish release / publish (push) Successful in 1m54s
The key is typed in the plist, and each payload carried a string where
the top level carried an integer - which iOS may refuse outright. A test
now holds all three to the same type.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
2026-10-07 11:25:08 +02:00
4 changed files with 16 additions and 4 deletions
+4
View File
@@ -4,6 +4,10 @@ One line per change, grouped by the release that shipped it. Newest
first. A release is a Cargo.toml bump plus a `v<version>` tag; the first. A release is a Cargo.toml bump plus a `v<version>` tag; the
content repos pin the tag they run (see the end of this file). content repos pin the tag they run (see the end of this file).
## 0.6.23 (2026-10-07)
- A configuration profile's per-payload `PayloadVersion` is an integer, as the plist key is typed; it was a string, which iOS may refuse.
## 0.6.22 (2026-10-07) ## 0.6.22 (2026-10-07)
- `/profile.mobileconfig` renders an Apple configuration profile from the mail server's own PACC document (`profile.pacc` in `site.yaml`), so iOS can be set up in one install instead of probing for ports it cannot reach. Mail, CalDAV and CardDAV in one profile; every host, port and path from PACC, never written down twice; no address, username or password in the document, so one profile serves everyone and iOS asks at install; identifiers derived from the site, so reinstalling replaces the accounts rather than duplicating them (docs: content-reference, "A configuration profile"). - `/profile.mobileconfig` renders an Apple configuration profile from the mail server's own PACC document (`profile.pacc` in `site.yaml`), so iOS can be set up in one install instead of probing for ports it cannot reach. Mail, CalDAV and CardDAV in one profile; every host, port and path from PACC, never written down twice; no address, username or password in the document, so one profile serves everyone and iOS asks at install; identifiers derived from the site, so reinstalling replaces the accounts rather than duplicating them (docs: content-reference, "A configuration profile").
Generated
+1 -1
View File
@@ -3357,7 +3357,7 @@ dependencies = [
[[package]] [[package]]
name = "portal" name = "portal"
version = "0.6.22" version = "0.6.23"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "portal" name = "portal"
version = "0.6.22" version = "0.6.23"
edition = "2021" edition = "2021"
[lib] [lib]
+10 -2
View File
@@ -148,7 +148,7 @@ pub fn render(pacc: &str, domain: &str, cfg: &ProfileConfig) -> anyhow::Result<S
count += 1; count += 1;
payloads.push_str("\t\t<dict>\n"); payloads.push_str("\t\t<dict>\n");
payloads.push_str(&string("PayloadType", "com.apple.mail.managed")); payloads.push_str(&string("PayloadType", "com.apple.mail.managed"));
payloads.push_str(&string("PayloadVersion", "1")); payloads.push_str(&integer("PayloadVersion", 1));
payloads.push_str(&string("PayloadIdentifier", &format!("{base}.mail"))); payloads.push_str(&string("PayloadIdentifier", &format!("{base}.mail")));
payloads.push_str(&string( payloads.push_str(&string(
"PayloadUUID", "PayloadUUID",
@@ -207,7 +207,7 @@ pub fn render(pacc: &str, domain: &str, cfg: &ProfileConfig) -> anyhow::Result<S
}; };
payloads.push_str("\t\t<dict>\n"); payloads.push_str("\t\t<dict>\n");
payloads.push_str(&string("PayloadType", kind)); payloads.push_str(&string("PayloadType", kind));
payloads.push_str(&string("PayloadVersion", "1")); payloads.push_str(&integer("PayloadVersion", 1));
payloads.push_str(&string("PayloadIdentifier", &format!("{base}.{proto}"))); payloads.push_str(&string("PayloadIdentifier", &format!("{base}.{proto}")));
payloads.push_str(&string( payloads.push_str(&string(
"PayloadUUID", "PayloadUUID",
@@ -338,6 +338,14 @@ mod tests {
fn every_value_comes_from_the_pacc_document() { fn every_value_comes_from_the_pacc_document() {
let p = render(PACC, "example.no", &cfg()).unwrap(); let p = render(PACC, "example.no", &cfg()).unwrap();
assert!(p.contains("<string>com.apple.mail.managed</string>")); assert!(p.contains("<string>com.apple.mail.managed</string>"));
// PayloadVersion is an integer everywhere, top level and in each
// payload: iOS reads the profile as a plist and the key is typed.
assert_eq!(
p.matches("<key>PayloadVersion</key>\n\t\t\t<integer>1</integer>")
.count(),
3
);
assert!(!p.contains("<key>PayloadVersion</key>\n\t\t\t<string>"));
assert!(p.contains("<string>com.apple.caldav.account</string>")); assert!(p.contains("<string>com.apple.caldav.account</string>"));
assert!(p.contains("<string>com.apple.carddav.account</string>")); assert!(p.contains("<string>com.apple.carddav.account</string>"));
assert!(p.contains( assert!(p.contains(