diff --git a/internal/clientconfig/applemail.go b/internal/clientconfig/applemail.go
index eba6f0f7..6b598818 100644
--- a/internal/clientconfig/applemail.go
+++ b/internal/clientconfig/applemail.go
@@ -21,6 +21,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "strings"
"time"
"github.com/ProtonMail/proton-bridge/v3/internal/useragent"
@@ -70,24 +71,24 @@ func prepareMobileConfig(
password []byte,
) *mobileconfig.Config {
return &mobileconfig.Config{
- DisplayName: username,
- EmailAddress: addresses,
- AccountName: displayName,
- AccountDescription: username,
- Identifier: "protonmail " + username + strconv.FormatInt(time.Now().Unix(), 10),
+ DisplayName: escapeXMLString(username),
+ EmailAddress: escapeXMLString(addresses),
+ AccountName: escapeXMLString(displayName),
+ AccountDescription: escapeXMLString(username),
+ Identifier: escapeXMLString("protonmail " + username + strconv.FormatInt(time.Now().Unix(), 10)),
IMAP: &mobileconfig.IMAP{
- Hostname: hostname,
+ Hostname: escapeXMLString(hostname),
Port: imapPort,
TLS: imapSSL,
- Username: username,
- Password: string(password),
+ Username: escapeXMLString(username),
+ Password: escapeXMLString(string(password)),
},
SMTP: &mobileconfig.SMTP{
- Hostname: hostname,
+ Hostname: escapeXMLString(hostname),
Port: smtpPort,
TLS: smtpSSL,
- Username: username,
- Password: string(password),
+ Username: escapeXMLString(username),
+ Password: escapeXMLString(string(password)),
},
}
}
@@ -121,3 +122,13 @@ func saveConfigTemporarily(mc *mobileconfig.Config) (fname string, err error) {
return
}
+
+// escapeXMLString replace all occurrences of the 5 characters `&`, `<`, `>`, `"` and `'` by their respective escaped version as per the XML spec.
+// https://www.w3.org/TR/xml/#syntax
+func escapeXMLString(input string) string {
+ result := strings.ReplaceAll(input, `&`, `&`)
+ result = strings.ReplaceAll(result, `<`, `<`)
+ result = strings.ReplaceAll(result, `>`, `>`)
+ result = strings.ReplaceAll(result, `"`, `"`)
+ return strings.ReplaceAll(result, `'`, `'`)
+}
diff --git a/internal/clientconfig/applemail_test.go b/internal/clientconfig/applemail_test.go
new file mode 100644
index 00000000..68036d03
--- /dev/null
+++ b/internal/clientconfig/applemail_test.go
@@ -0,0 +1,38 @@
+// Copyright (c) 2024 Proton AG
+//
+// This file is part of Proton Mail Bridge.
+//
+// Proton Mail Bridge is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Proton Mail Bridge is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Proton Mail Bridge. If not, see .
+
+//go:build darwin
+
+package clientconfig
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestEscapeXMLString(t *testing.T) {
+ require.Equal(t, escapeXMLString(`abc&&''""<<>>def`), `abc&&''""<<>>def`)
+}
+
+// This test requires human interaction (user configuration profile installation prompt). It is for debugging purpose and is disabled by default.
+func _TestInstallCert(t *testing.T) { //nolint:unused
+ require.NoError(
+ t,
+ (&AppleMail{}).Configure(`127.0.0.1`, 1143, 1025, true, false, `user&>>`, `<>`, `user&a`, []byte(`ir8R9vhdNXyB7isWzhyEkQ`)),
+ )
+}