Writing your own content-blocker for Safari 9 in El Capitan: 1

Of all the new features in OS X 10.11 El Capitan, the most controversial is that of content-blocking through its new Safari version 9, equivalent to Safari 9 in iOS 9.

Because of the way in which iOS security works, users cannot develop their own content-blockers for Safari 9 on iOS. For the time being, the only way that you can make your own iOS content blocker is to obtain Xcode from the Mac App Store, and use that to build your blocker.

To create your own content-blocker for Safari 9 for OS X, all you need is a copy of Safari and your own Safari Extension Certificate. The latter is required, as Apple now enforces code signing in Safari Extensions; this certificate allows your Mac to create properly signed Safari Extensions, which can then be installed and used. Details of the process of registering for a Safari Extension Certificate are given here.

A content-blocking extension is best created as a single JSON text file, which is loaded and packaged using the Safari Extension Builder. Before you can access that, if you have not done so already, you must enable Safari’s Develop menu. To do that, open Safari’s Preferences, and select the Advanced Tool. At the foot of the dialog, you will see a check item labelled ‘Show Develop menu in menu bar’, which needs to be checked.

Create your blocker using a plain text editor (set in JSON format if available), then you can generate the complete Safari Extension using the Extension Builder tool in Safari; this is opened by the Show Extension Builder command in the Develop menu.

JSON, JavaScript Object Notation, is a standard scheme for laying out data in pairs of attributes and their values, not dissimilar to XML. It is very pernicketty when it comes to punctuation and spelling, but far less interested in white space and layout. A text editor such as BBEdit, which has custom settings to help you format and edit JSON, is ideal.

A really basic content-blocker might have a JSON definition which looks like:

[
{
"action": {
"type": "block"
},
"trigger": {
"url-filter": "https?://(www.)?nastysite.*"
}
}
]

Each rule in the blocker consists of an action and trigger pair, in which the trigger specifies the page content which will trigger the action by Safari. In the above, Safari (or actually WebKit within Safari) will filter URLs so that any which match the regular expression
https?://(www.)?nastysite.*
will result in the action being triggered, here the site being blocked from loading.

https?
is a regular expression which includes both http and https, as it means ‘the letters http, followed by 0 or 1 s characters’. Similarly
(www.)?nastysite.*
means ‘0 or 1 occurrences of www. followed by the text nastysite. followed by any text’.

If you need to refresh your mind on regular expressions, my introduction should be a good starting point.

This basic type of URL filter will block whole web pages from being loaded, but will not block page elements which might be embedded in other sites. To block those, you need to use CSS selectors, as in:

[
{
"action": {
"type": "css-display-none",
"selector": "a[href*='www.nastysite']"
},
"trigger": {
"url-filter": ".*"
}
}
]

The above blocker will be applied to all URLs, because of its catch-all trigger, and will then select the content from any given URL according to the rule in the action. That simply turns off display when the content contains a link to http://www.nastysite.

contentblock2By combining these two rules, your blocker can prevent the display of all content from the specified website, and the great majority of external content which points to it:

[
{
"action": {
"type": "block"
},
"trigger": {
"url-filter": "https?://(www.)?nastysite.*"
}
},
{
"action": {
"type": "css-display-none",
"selector": "a[href*='www.nastysite']"
},
"trigger": {
"url-filter": ".*"
}
}
]

There are additional tutorials on Surfin’ Safari and Hacking with Swift.

In the next article in this series, I will look at other actions and triggers which you can use to create more sophisticated blocks.