| 123456789101112131415161718192021222324252627282930313233 |
- // LoopFollow
- // APNsCredentialValidator.swift
- import Foundation
- /// Validation rules for the APNs credentials the user pastes in
- /// `APNSettingsView`. Used both by the settings UI to surface inline
- /// errors and by `LiveActivitySettingsView` to warn when push-based
- /// updates won't work.
- enum APNsCredentialValidator {
- /// Apple Key IDs are exactly 10 uppercase alphanumeric characters.
- static func isValidKeyId(_ keyId: String) -> Bool {
- guard keyId.count == 10 else { return false }
- return keyId.allSatisfy { $0.isASCII && ($0.isUppercase || $0.isNumber) }
- }
- /// A pasted .p8 must contain both PEM markers. We don't try to verify
- /// the inner base64 here — `LoopAPNSService.validateAndFixAPNSKey`
- /// already normalizes whitespace and logs deeper warnings, and we
- /// don't want to reject keys that JWTManager would happily sign.
- static func isValidApnsKey(_ key: String) -> Bool {
- let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines)
- guard !trimmed.isEmpty else { return false }
- return trimmed.contains("-----BEGIN PRIVATE KEY-----")
- && trimmed.contains("-----END PRIVATE KEY-----")
- }
- /// Convenience for "is the user fully set up to send APNs pushes?"
- static func isFullyConfigured(keyId: String, apnsKey: String) -> Bool {
- isValidKeyId(keyId) && isValidApnsKey(apnsKey)
- }
- }
|