BOOL TNLErrorIsNetworkSecurityError()

in Source/TNLError.m [125:182]


BOOL TNLErrorIsNetworkSecurityError(NSError * __nullable error)
{
    NSString * const domain = error.domain;
    NSInteger code = error.code;
    if ([domain isEqualToString:TNLErrorDomain] && TNLErrorCodeRequestOperationAuthenticationChallengeCancelled == code) {
        // auth challenge failed
        return YES;
    }

    if (![domain isEqualToString:NSURLErrorDomain] && ![domain isEqualToString:(NSString *)kCFErrorDomainCFNetwork]) {
        // not an internet failure
        return NO;
    }

    // Conveniently, NSURL errors and CFNetwork errors share the same error code values

    if (-1022 == code) {
        // Insecure request violates ATS
        return YES;
    } else if (-1200 == code) {
        // skip! - this is SSL connection failure
        // which is a network failure, not a security failure
    } else if (code <= -1201 && code >= -1206) {
        // SSL error
        return YES;
    } else if (-2000 == code) {

#if !TARGET_OS_WATCH
        // cannot load from network - is it due to SSL?

        if (nil != error.userInfo[(NSString *)kCFStreamPropertySSLPeerTrust]) {
            // short cut - we have a "trust" which implicates network security
            return YES;
        }

        // Some network errors can be underpinned by CFStream errors,
        // which are not wrapped in an `NSError`,
        // so we can look at the userInfo for specific keys
        // (namely _kCFStreamErrorDomainKey and _kCFStreamErrorDomainCode)
        id domainNumber = error.userInfo[@"_kCFStreamErrorDomainKey"];
        if ([domainNumber respondsToSelector:@selector(intValue)]) {
            if (kCFStreamErrorDomainSSL == [domainNumber intValue]) {
                // It is an SSL error, treat as security error
                // NOTE: there is a more specific subset of error codes which we are ignoring (see Security/SecureTransport.h)
                return YES;
            }
        }
#endif // !WATCH
    }

    NSError * const underlyingError = error.userInfo[NSUnderlyingErrorKey];
    if (underlyingError) {
        // recurse to see if the underlying error is network security related
        return TNLErrorIsNetworkSecurityError(underlyingError);
    }

    return NO;
}