Search code examples
iosswiftreporting-servicesreportingios-extensions

HTTP Request Fails Trying to Report Unwanted Communication Report via API


I created an Unwanted Communication Reporting Extension as per described here: https://developer.apple.com/documentation/sms_and_call_reporting/sms_and_call_spam_reporting

Followed the instructions and was able to get the report callback in my extension class, but when I try to make an API request to my HTTPS server, somewhere along the console log I get

nw_resolver_can_use_dns_xpc_block_invoke Sandbox does not allow access to com.apple.dnssd.service

and

Task <C31ADB51-B5C3-4E85-800E-405781F6A9ED>.<1> finished with error [-1003] Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={_kCFStreamErrorCodeKey=-72000, NSUnderlyingError=0x282d5c600 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, _kCFStreamErrorCodeKey=-72000, _kCFStreamErrorDomainKey=10}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <C31ADB51-B5C3-4E85-800E-405781F6A9ED>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <C31ADB51-B5C3-4E85-800E-405781F6A9ED>.<1>"), NSLocalizedDescription=A server with the specified hostname could not be found., NSErrorFailingURLStringKey=https://sub.domain.com/debug, NSErrorFailingURLKey=https://sub.domain.com/debug, _kCFStreamErrorDomainKey=10}

So basically the dns lookup fails due to a sandbox restriction, but I was not able to allow the app sandbox access, that seems like a OSX specific capability.

Here is my code example that is in charge of the API reporting:

func reportToAPI(for request: ILClassificationRequest) {
    
    let payload: [String: AnyHashable] = [
        "data": "OK",
        "test": "payload"
    ]
    
    guard let url = URL(string: "https://sub.domain.com/debug") else {
        return
    }
    
    var request = URLRequest(url: url)
    
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: payload, options: .fragmentsAllowed)
    
    let task = URLSession.shared.dataTask(with: request) { data, _, error in
        guard let data = data, error == nil else {
            return
        }
        
        do {
            let response = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
            print(response)
        } catch {
            
        }
    }
    task.resume()
}

I also have my associated domains set up on both extension and main app's target as classificationreport:sub.domain.com and domain.com, as well as my apple-app-site-association file uploaded as this:

{
"classificationreport": {
    "apps": ["L***.com.b***.smsreporting.unwantedreporting","L***.com.b***.smsreporting"]
}

Any help and guidance is appreciated as I am stuck at this point and lack of documentation on this is making things harder.

Edit: I am testing this on my own developer account, which is an individual membership, not organizational, if that matters.


Solution

  • It seems you call reportToAPI() in Unwanted Communication Reporting Extension.

    However if you add apple-app-site-association and Association Domain in .entitlement correctly. There is no need to create URLRequest by yourself. Apple will send the API on your behalf. (I think it's for privacy reasons, like Message Filter Extension.)

    So classificationResponse should look like this:

    override func classificationResponse(for request:ILClassificationRequest) -> ILClassificationResponse {
        let payload: [String: AnyHashable] = [
            "data": "OK",
            "test": "payload"
        ]
        let action: ILClassificationAction = .reportJunk  // or .none, .reportNotJunk, .reportJunkAndBlockSender
        let response = ILClassificationResponse(action: action)
        response.userInfo = payload
    
        return response
    }