File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -40,10 +40,10 @@ class NightscoutSocketManager {
4040 return
4141 }
4242
43- let url = Storage . shared. url. value
44- // Sanitize defensively: tokens saved before this fix may still hold a stray
43+ // Sanitize defensively: values saved before this fix may still hold a stray
4544 // whitespace/control char that crashes Socket.IO's URL builder on iOS 26.
46- let token = NightscoutUtils . sanitizeToken ( Storage . shared. token. value)
45+ let url = NightscoutUtils . sanitizeConnectionInput ( Storage . shared. url. value)
46+ let token = NightscoutUtils . sanitizeConnectionInput ( Storage . shared. token. value)
4747
4848 guard !url. isEmpty else {
4949 disconnect ( )
Original file line number Diff line number Diff line change @@ -163,9 +163,11 @@ class NightscoutUtils {
163163 }
164164
165165 // Strip whitespace/newlines/control characters that can sneak in via paste.
166- // A raw one breaks WebSocket connect (invalid percent-encoded query traps on iOS 26).
167- static func sanitizeToken( _ token: String ) -> String {
168- token. unicodeScalars
166+ // Neither a URL nor a token may legally contain them, and a stray one breaks
167+ // WebSocket connect (invalid percent-encoded query traps on iOS 26) or makes
168+ // URL parsing fall back to a lossy cleanup that mangles the address.
169+ static func sanitizeConnectionInput( _ input: String ) -> String {
170+ input. unicodeScalars
169171 . filter { !CharacterSet. whitespacesAndNewlines. contains ( $0) && !CharacterSet. controlCharacters. contains ( $0) }
170172 . map ( String . init)
171173 . joined ( )
Original file line number Diff line number Diff line change @@ -27,7 +27,7 @@ class NightscoutSettingsViewModel: ObservableObject {
2727 @Published var nightscoutToken : String = Storage . shared. token. value {
2828 willSet {
2929 if newValue != nightscoutToken {
30- Storage . shared. token. value = NightscoutUtils . sanitizeToken ( newValue)
30+ Storage . shared. token. value = NightscoutUtils . sanitizeConnectionInput ( newValue)
3131 triggerCheckStatus ( )
3232 }
3333 }
@@ -93,6 +93,12 @@ class NightscoutSettingsViewModel: ObservableObject {
9393 }
9494
9595 func processURL( _ value: String ) {
96+ // Strip whitespace/newlines/control chars first. A URL can't legally contain
97+ // them, and a stray one (e.g. a trailing newline from a paste) otherwise makes
98+ // URLComponents parsing fail and falls through to the lossy fallback below,
99+ // mangling a URL-with-embedded-token into an invalid address.
100+ let value = NightscoutUtils . sanitizeConnectionInput ( value)
101+
96102 var useTokenUrl = false
97103
98104 if let urlComponents = URLComponents ( string: value) , let queryItems = urlComponents. queryItems {
You can’t perform that action at this time.
0 commit comments