Content Blocker Extension with a String Instead of a File

Content Blocker extension with a String instead of a file

By loading the extension up in the debugger (and by using Hopper), you can see that NSItemProvider(contentsOfURL:) is simply registering to provide data from the file's contents with type public.json.

(lldb) po attachment
<NSItemProvider: 0x7fd4c250f2a0> {types = (
"public.file-url",
"public.json"
)}

It's roughly equivalent to this:

// possible implementation of NSItemProvider.init(contentsOfURL:)
convenience init?(contentsOfURL fileURL: NSURL!)
{
self.init(item: fileURL, typeIdentifier: (fileURL.fileURL ? kUTTypeFileURL : kUTTypeURL) as String)

let type = UTTypeCreatePreferredIdentifierForTag(
kUTTagClassFilenameExtension, fileURL.pathExtension!, nil)?.takeRetainedValue() as! String

registerItemForTypeIdentifier(type) { completionHandler, expectedValueClass, options in
let data = try! NSData(contentsOfURL: fileURL, options: .DataReadingMappedAlways)
completionHandler(data, nil)
}
}

So you can do this yourself, in memory:

// get the data
let data = NSData(contentsOfURL: NSBundle.mainBundle().URLForResource("blockerList", withExtension: "json")!)

// put the data in an item provider
let attachment = NSItemProvider(item: data, typeIdentifier: kUTTypeJSON as String)

// send the item to Safari
let item = NSExtensionItem()
item.attachments = [attachment]
context.completeRequestReturningItems([item], completionHandler: nil);

If you want to provide content dynamically, you can use NSJSONSerialization to transform a dictionary into NSData at runtime.

iOS Content Blocking Extension Loading Multiple JSON Files

For those curious I ended up adding code to dynamically generate a JSON file (persisted to disk). From other answers it seems like the step of saving could be avoided by returning an NSData representation of the file instead - although that attempt failed for me. Here's my snippet:

import UIKit
import MobileCoreServices

class ActionRequestHandler: NSObject, NSExtensionRequestHandling {

func beginRequestWithExtensionContext(context: NSExtensionContext) {
let item = NSExtensionItem()
let items = [item]

let url = buildJSONFileURL()
if let attachment = NSItemProvider(contentsOfURL: url) { item.attachments = [attachment] }

context.completeRequestReturningItems(items, completionHandler: nil)
}

func buildJSONFileURL() -> NSURL {
let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let directory = directories[0]

let path = directory.stringByAppendingFormat("/block.json")

let selector = [...] // Dynamically Generated
let dictionary = [[
"action": [ "type": "css-display-none", "selector": selector ],
"trigger": [ "url-filter": ".*" ]
]]

let data = try! NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions.PrettyPrinted)
let text = NSString(data: data, encoding: NSASCIIStringEncoding)!

try! text.writeToFile(path, atomically: true, encoding: NSASCIIStringEncoding)

return NSURL(fileURLWithPath: path)
}

}

How to trim a file extension from a String in JavaScript?

If you know the length of the extension, you can use x.slice(0, -4) (where 4 is the three characters of the extension and the dot).

If you don't know the length @John Hartsock regex would be the right approach.

If you'd rather not use regular expressions, you can try this (less performant):

filename.split('.').slice(0, -1).join('.')

Note that it will fail on files without extension.

Can a website block a Chrome Extension?

For the short Answer to the question goto the 4th Edit:

You need to know the extensionId from the Extension you want to block, so that it works.

Here is a Testsite from the Prove of Concept
Testsite

and here is the information behind the Solution:
Intro to Chrome addons hacking: fingerprinting

Now that you know what Extensions are Running you can, redirect/block/...

I hope it helps.

Edit:

Tested with (Chrome Version 27.0.1453.94) on Windows XP

Edit 2:

This technique will only work if:

  1. You know the extensionid :)
  2. IMPORTANT! at least one Ressource(like the manifest.json, some image, script, ...)
    is set as "web_accessible_resources" (in the manifest) OR the
    extension still uses a manifest version 1 and has no "web_accessible_resources" set. (Ressource from chrome dev site Link)

Edit 3:

Case Extension: JSONView

You could detect the extension with this code(only example code):

<script src="chrome-extension://chklaanhfefbnpoihckbnefhakgolnmc/error.gif" onerror="console.info('Extension Not Found')" onload="console.info('Extension Found')"></script>
<!-- since the the file error.gif is allowed in the manifest "web_accessible_resources" (any other file mentioned there would also be fine) -->
<!-- the block code should come in the onload of the script tag -->
<!-- tested with Chrome 27+ WinXp -->

Some Context:
The JSONView Extension has a version 2 Manifest:

...
"manifest_version": 2,
"name": "JSONView",
...

so by default you cannot access the manifest file as mentioned in the "Prove of Concept" above.

BUT it uses the "web_accessible_resources" attribute in the Manifest, which allows websites to access files from the Extension.

...
"web_accessible_resources": [ "jsonview.css", "jsonview-core.css", "content_error.css", "options.png", "close_icon.gif", "error.gif" ]
...

So now you can call any of this files from your webpage.

example:

chrome-extension://chklaanhfefbnpoihckbnefhakgolnmc/error.gif
chrome-extension://chklaanhfefbnpoihckbnefhakgolnmc/jsonview.css
...

And with this url in an Image/Script/.. -Tag you can know if the extension is there, if the onload Event fires.

P.s.: i only tested this with Chrome Version 27.0.1453.94) on Windows XP, in other Versions it might not work. (see comment from T.J. Crowder)

P.P.s.: For More Details check the Chrome Developer Ressources. Here is the Link to the Extension on the Chrome Ressource Page "Finger printing" Stuff)

Edit 4:

I don't think it can be blocked per se, but if you can detect the extension as mentioned above you could:

  • redirect away from your Page
  • or Popup a message(every few seconds) saying, "disable the extension for this Site"
  • or you could check the Extension code to see if you maybe could "break" or hinder its functionality.
  • or you could use some Code like in the answer of BeardFist

How to I get all files from a directory with a variable extension of specified length?

I don't believe there's a way you can do this without looping through the files in the directory and its subfolders. The search pattern for GetFiles doesn't support regular expressions, so we can't really use something like [\d]{7} as a filter. I would suggest using Directory.EnumerateFiles and then return the files that match your criteria.

You can use this to enumerate the files:

private static IEnumerable<string> GetProprietaryFiles(string topDirectory)
{
Func<string, bool> filter = f =>
{
string extension = Path.GetExtension(f);
// is 8 characters long including the .
// all remaining characters are digits
return extension.Length == 8 && extension.Skip(1).All(char.IsDigit);
};

// EnumerateFiles allows us to step through the files without
// loading all of the filenames into memory at once.
IEnumerable<string> matchingFiles =
Directory.EnumerateFiles(topDirectory, "*", SearchOption.AllDirectories)
.Where(filter);

// Return each file as the enumerable is iterated
foreach (var file in matchingFiles)
{
yield return file;
}
}

Path.GetExtension includes the . so we check that the number of characters including the . is 8, and that all remaining characters are digits.

Usage:

List<string> fileList = GetProprietaryFiles(someDir).ToList();


Related Topics



Leave a reply



Submit