1

I am trying to make a content filter that censors webpages automatically by replacing the text of webpages with better alternatives ($'s and *'s in place of expletives, for example).

I found this pretty easy to do when creating an action extension, which lets you modify the webpage pretty easily. But for the actions in content filters, I'm not sure how to do this.

I figure that the code will need to look something like this:

[
    {
        "trigger": {
            "resource-type": ["script"]
        },
        "action": {
            "type": "css-display-none",
            "selector": "???"
        }
    }
]

"type": "css-display-none" seems like the only way for this to work, because the other types (block, block-cookies, and ignore-previous-rules) don't seem relevant here. However, I can't figure out how to replace text using CSS selectors.

I looked at this CSS selectors website that Apple referenced, but couldn't come up with a solution.

Edit

I am trying a different approach using Javascript instead of CSS, more like how the action extension works. I added the Javascript prototype to the Info.plist as the NSExtensionJavaScriptPreprocessingFile.

For some reason this code seems to do nothing. Why is the same code from the action extension not working in the content filter?

class ActionRequestHandler: NSObject, NSExtensionRequestHandling {

    var extensionContext: NSExtensionContext?

    func beginRequestWithExtensionContext(context: NSExtensionContext) {
        self.extensionContext = context

        for item: AnyObject in context.inputItems {

            let inputItem = item as! NSExtensionItem

            for provider: AnyObject in inputItem.attachments! {

                let itemProvider = provider as! NSItemProvider

                if itemProvider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) {

                    itemProvider.loadItemForTypeIdentifier(kUTTypePropertyList as String, options: nil, completionHandler: { [unowned self] (result, error) in
                        if let dictionary = result as? NSDictionary {
                            self.itemLoadCompletedWithPreprocessingResults(dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as! [NSObject: AnyObject])
                        }

                        })

                }
            }
        }
    }

    func itemLoadCompletedWithPreprocessingResults(javaScriptPreprocessingResults: [NSObject: AnyObject]) {
        let pageContent = javaScriptPreprocessingResults["content"] as! NSString
        let fixedContent = pageContent.stringByReplacingOccurrencesOfString("Bad Word", withString: "Good Word")
        self.doneWithResults(["content": fixedContent])
    }

    func doneWithResults(resultsForJavaScriptFinalizeArg: [NSObject: AnyObject]?) {
        if let resultsForJavaScriptFinalize = resultsForJavaScriptFinalizeArg {

            let resultsDictionary = [NSExtensionJavaScriptFinalizeArgumentKey: resultsForJavaScriptFinalize]

            let resultsProvider = NSItemProvider(item: resultsDictionary, typeIdentifier: String(kUTTypePropertyList))

            let resultsItem = NSExtensionItem()
            resultsItem.attachments = [resultsProvider]

            self.extensionContext!.completeRequestReturningItems([resultsItem], completionHandler: nil)
        } else {
            self.extensionContext!.completeRequestReturningItems([], completionHandler: nil)
        }

        self.extensionContext = nil
    }

}

Javascript action:

var Action = function() {};

Action.prototype = {

run: function(arguments) {
    arguments.completionFunction({"content": document.body.innerHTML});
},

finalize: function(arguments) {
    document.body.innerHTML = arguments["content"];
}

};

var ExtensionPreprocessingJS = new Action
erdekhayser
  • 6,537
  • 2
  • 37
  • 69
  • CSS can't detect text (yet)...you need Javascript for that. – Paulie_D Mar 20 '16 at 12:58
  • You'd need to have an array of 'offensive' words. Have JS parse **all the text on the page**, check it for strings matching your array and then either substitute the text or wrap it in a `span` and hide it. Oh...and have some sort of secondary array of permitted words that contain offensive words..like **Scunthorpe**. Plus I can get around your filter with very little difficulty. After all, if I use an epithet like d\*ck...I've bypassed your filter and it's still clear what I meant. You're fighting a losing battle here my friend. – Paulie_D Mar 20 '16 at 13:01
  • @Paulie_D It's more as a proof-of-concept that I may put out than a fight against disagreeable words. About your suggestion, I am trying to use Javascript for the content filter like I am using in the action extension, but that isn't working for some reason. I'll update the question with more info on that. – erdekhayser Mar 20 '16 at 13:20
  • Reading the Apple documentation more closely, it seems that this behavior is not supported. Content blocking (not filtering) must be done in a structured format and does not execute any code. – erdekhayser Mar 20 '16 at 13:50

0 Answers0