Merge pull request #64 from osnr/safari

Safari support
This commit is contained in:
Omar Rizwan 2021-02-14 16:45:07 -08:00 committed by GitHub
commit 5350b73c2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1586 additions and 0 deletions

View file

@ -673,6 +673,10 @@ function findRoute(path) {
let port;
async function onMessage(req) {
// Safari / Safari extension app API forces you to adopt their
// {name, userInfo} structure for the request.
if (req.name === 'ToSafari') req = req.userInfo;
if (req.buf) req.buf = atob(req.buf);
console.log('req', req);
@ -709,6 +713,37 @@ async function onMessage(req) {
};
function tryConnect() {
// Safari is very weird -- it has this native app that we have to talk to,
// so we poke that app to wake it up, get it to start the TabFS process
// and boot a WebSocket, then connect to it.
// Is there a better way to do this?
if (chrome.runtime.getURL('/').startsWith('safari-web-extension://')) { // Safari-only
chrome.runtime.sendNativeMessage('com.rsnous.tabfs', {op: 'safari_did_connect'}, resp => {
console.log(resp);
let socket;
function connectSocket(checkAfterTime) {
socket = new WebSocket('ws://localhost:9991');
socket.addEventListener('message', event => {
onMessage(JSON.parse(event.data));
});
port = { postMessage(message) {
socket.send(JSON.stringify(message));
} };
setTimeout(() => {
if (socket.readyState !== 1) {
console.log('ws connection failed, retrying in', checkAfterTime);
connectSocket(checkAfterTime * 2);
}
}, checkAfterTime);
}
connectSocket(200);
});
return;
}
port = chrome.runtime.connectNative('com.rsnous.tabfs');
port.onMessage.addListener(onMessage);
port.onDisconnect.addListener(p => {console.log('disconnect', p)});

View file

@ -0,0 +1,35 @@
## TabFS for Safari
This support is a work in progress (as are these instructions).
Safari's extension support is pretty messy. You will need:
- Xcode installed
- Safari 14 or newer
- macOS 10.15 Catalina or newer
Enable the Develop menu in Safari, then Develop -> Allow Unsigned
Extensions.
Open the Xcode project `TabFS/TabFS.xcodeproj` in this directory. Run
the project. It should open a TabFS app and install the extension in
Safari.
Enable the extension in Safari Preferences, grant it access to all
sites. It should be running now! (?)
Check the `fs/mnt` folder of the TabFS repo on your computer to see if
it's mounted.
### tips
- To open Web inspector: Safari -> Develop menu -> Web Extension
Background Pages -> TabFS.
Refreshing this inspector should reload the tabfs filesystem, also.
- You need to rebuild in Xcode any time you change background.js
(because the extension files are copied into the extension, rather
than running directly from folder as in Firefox and Chrome). This is
pretty annoying.

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>TabFS Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.Safari.web-extension</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).SafariWebExtensionHandler</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,62 @@
//
// SafariWebExtensionHandler.swift
// TabFS Extension
//
// Created by Omar Rizwan on 1/31/21.
//
import SafariServices
import os.log
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
let item = context.inputItems[0] as! NSExtensionItem
guard let message = item.userInfo?["message"] as? [AnyHashable: Any] else { return }
guard message["op"] as! String == "safari_did_connect" else { return }
// The XPC service is a process that can live outside the macOS App Sandbox.
// (Safari extension native code, including this file, has to live in the sandbox.)
// It can do forbidden things like spawn tabfs filesystem and set up WebSocket server.
// We only use one native message, to bootstrap the XPC service (TabFSService).
// Then the XPC service starts TabFSServer. TabFSServer is separate because
// XPC services get killed by the OS after a minute or two; TabFSServer
// is just a normal process that can live on. It talks straight
// to background.js (which in turn talks to tabfs.c) over a WebSocket.
// (Safari makes doing native messaging quite painful, so we try to avoid it.
// It forces the browser to pop to front if you message Safari in the obvious way,
// for instance: https://developer.apple.com/forums/thread/122232
// And with the WebSocket, the server can talk straight to background.js, whereas
// native messaging would require us here to sit in the middle.)
let connection = NSXPCConnection(serviceName: "com.rsnous.TabFSService")
connection.remoteObjectInterface = NSXPCInterface(with: TabFSServiceProtocol.self)
connection.resume()
let service = connection.remoteObjectProxyWithErrorHandler { error in
os_log(.default, "Received error: %{public}@", error as CVarArg)
} as? TabFSServiceProtocol
// Need this one XPC call to actually initialize the service.
service?.start() {
os_log(.default, "Response from XPC service")
// FIXME: report port back?
let response = NSExtensionItem()
response.userInfo = [ "message": "alive" ]
// This response (over native messaging) will prompt background.js to
// connect to the WebSocket server of TabFSServer, which should
// now be running.
context.completeRequest(returningItems: [response]) { (what) in
print(what)
}
}
return
}
}

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.all</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,749 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
F028D2B625D0B7370095C2D5 /* TabFSService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B525D0B7370095C2D5 /* TabFSService.swift */; };
F028D2B825D0B7370095C2D5 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B725D0B7370095C2D5 /* main.swift */; };
F028D2D725D0B8500095C2D5 /* TabFSServiceProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B325D0B7370095C2D5 /* TabFSServiceProtocols.swift */; };
F028D2DE25D0B8590095C2D5 /* TabFSServiceProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B325D0B7370095C2D5 /* TabFSServiceProtocols.swift */; };
F028D2ED25D106F10095C2D5 /* TabFSService.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = F028D2B125D0B7370095C2D5 /* TabFSService.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
F028D30125D17B080095C2D5 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D30025D17B080095C2D5 /* main.swift */; };
F028D34525D17D6A0095C2D5 /* TabFSServer in CopyFiles */ = {isa = PBXBuildFile; fileRef = F028D2FE25D17B080095C2D5 /* TabFSServer */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
F04429F625C7507200D998A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04429F525C7507200D998A5 /* AppDelegate.swift */; };
F04429F925C7507200D998A5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F04429F725C7507200D998A5 /* Main.storyboard */; };
F04429FB25C7507200D998A5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04429FA25C7507200D998A5 /* ViewController.swift */; };
F04429FD25C7507400D998A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F04429FC25C7507400D998A5 /* Assets.xcassets */; };
F0442A0425C7507400D998A5 /* TabFS Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = F0442A0325C7507400D998A5 /* TabFS Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
F0442A0925C7507400D998A5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0442A0825C7507400D998A5 /* Cocoa.framework */; };
F0442A0C25C7507400D998A5 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0442A0B25C7507400D998A5 /* SafariWebExtensionHandler.swift */; };
F0442A1D25C7507500D998A5 /* background.js in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1925C7507500D998A5 /* background.js */; };
F0442A1E25C7507500D998A5 /* safari in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1A25C7507500D998A5 /* safari */; };
F0442A1F25C7507500D998A5 /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1B25C7507500D998A5 /* manifest.json */; };
F0442A2025C7507500D998A5 /* vendor in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1C25C7507500D998A5 /* vendor */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F028D33725D17D100095C2D5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F04429E925C7507200D998A5 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F028D2FD25D17B080095C2D5;
remoteInfo = TabFSServer;
};
F0442A0525C7507400D998A5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F04429E925C7507200D998A5 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F0442A0225C7507400D998A5;
remoteInfo = "TabFS Extension";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
F028D2E525D106BB0095C2D5 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices";
dstSubfolderSpec = 16;
files = (
F028D2ED25D106F10095C2D5 /* TabFSService.xpc in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F028D2FC25D17B080095C2D5 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
F028D30E25D17BD20095C2D5 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 7;
files = (
F028D34525D17D6A0095C2D5 /* TabFSServer in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0442A1425C7507400D998A5 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
F0442A0425C7507400D998A5 /* TabFS Extension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
F028D2B125D0B7370095C2D5 /* TabFSService.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = TabFSService.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
F028D2B325D0B7370095C2D5 /* TabFSServiceProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabFSServiceProtocols.swift; sourceTree = "<group>"; };
F028D2B525D0B7370095C2D5 /* TabFSService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabFSService.swift; sourceTree = "<group>"; };
F028D2B725D0B7370095C2D5 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
F028D2B925D0B7370095C2D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F028D2FE25D17B080095C2D5 /* TabFSServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TabFSServer; sourceTree = BUILT_PRODUCTS_DIR; };
F028D30025D17B080095C2D5 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
F04429F125C7507200D998A5 /* TabFS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabFS.app; sourceTree = BUILT_PRODUCTS_DIR; };
F04429F425C7507200D998A5 /* TabFS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TabFS.entitlements; sourceTree = "<group>"; };
F04429F525C7507200D998A5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
F04429F825C7507200D998A5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
F04429FA25C7507200D998A5 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
F04429FC25C7507400D998A5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
F04429FE25C7507400D998A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F0442A0325C7507400D998A5 /* TabFS Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "TabFS Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
F0442A0825C7507400D998A5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
F0442A0B25C7507400D998A5 /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = "<group>"; };
F0442A0D25C7507400D998A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F0442A0E25C7507400D998A5 /* TabFS_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TabFS_Extension.entitlements; sourceTree = "<group>"; };
F0442A1925C7507500D998A5 /* background.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = background.js; path = ../../../background.js; sourceTree = "<group>"; };
F0442A1A25C7507500D998A5 /* safari */ = {isa = PBXFileReference; lastKnownFileType = folder; name = safari; path = ../..; sourceTree = "<group>"; };
F0442A1B25C7507500D998A5 /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = manifest.json; path = ../../../manifest.json; sourceTree = "<group>"; };
F0442A1C25C7507500D998A5 /* vendor */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vendor; path = ../../../vendor; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F028D2AE25D0B7370095C2D5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F028D2FB25D17B080095C2D5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F04429EE25C7507200D998A5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F0442A0025C7507400D998A5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F0442A0925C7507400D998A5 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F028D2B225D0B7370095C2D5 /* TabFSService */ = {
isa = PBXGroup;
children = (
F028D2B325D0B7370095C2D5 /* TabFSServiceProtocols.swift */,
F028D2B525D0B7370095C2D5 /* TabFSService.swift */,
F028D2B725D0B7370095C2D5 /* main.swift */,
F028D2B925D0B7370095C2D5 /* Info.plist */,
);
path = TabFSService;
sourceTree = "<group>";
};
F028D2FF25D17B080095C2D5 /* TabFSServer */ = {
isa = PBXGroup;
children = (
F028D30025D17B080095C2D5 /* main.swift */,
);
path = TabFSServer;
sourceTree = "<group>";
};
F04429E825C7507200D998A5 = {
isa = PBXGroup;
children = (
F04429F325C7507200D998A5 /* TabFS */,
F0442A0A25C7507400D998A5 /* TabFS Extension */,
F028D2B225D0B7370095C2D5 /* TabFSService */,
F028D2FF25D17B080095C2D5 /* TabFSServer */,
F0442A0725C7507400D998A5 /* Frameworks */,
F04429F225C7507200D998A5 /* Products */,
);
sourceTree = "<group>";
};
F04429F225C7507200D998A5 /* Products */ = {
isa = PBXGroup;
children = (
F04429F125C7507200D998A5 /* TabFS.app */,
F0442A0325C7507400D998A5 /* TabFS Extension.appex */,
F028D2B125D0B7370095C2D5 /* TabFSService.xpc */,
F028D2FE25D17B080095C2D5 /* TabFSServer */,
);
name = Products;
sourceTree = "<group>";
};
F04429F325C7507200D998A5 /* TabFS */ = {
isa = PBXGroup;
children = (
F04429F425C7507200D998A5 /* TabFS.entitlements */,
F04429F525C7507200D998A5 /* AppDelegate.swift */,
F04429F725C7507200D998A5 /* Main.storyboard */,
F04429FA25C7507200D998A5 /* ViewController.swift */,
F04429FC25C7507400D998A5 /* Assets.xcassets */,
F04429FE25C7507400D998A5 /* Info.plist */,
);
path = TabFS;
sourceTree = "<group>";
};
F0442A0725C7507400D998A5 /* Frameworks */ = {
isa = PBXGroup;
children = (
F0442A0825C7507400D998A5 /* Cocoa.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
F0442A0A25C7507400D998A5 /* TabFS Extension */ = {
isa = PBXGroup;
children = (
F0442A1825C7507500D998A5 /* Resources */,
F0442A0B25C7507400D998A5 /* SafariWebExtensionHandler.swift */,
F0442A0D25C7507400D998A5 /* Info.plist */,
F0442A0E25C7507400D998A5 /* TabFS_Extension.entitlements */,
);
path = "TabFS Extension";
sourceTree = "<group>";
};
F0442A1825C7507500D998A5 /* Resources */ = {
isa = PBXGroup;
children = (
F0442A1925C7507500D998A5 /* background.js */,
F0442A1A25C7507500D998A5 /* safari */,
F0442A1B25C7507500D998A5 /* manifest.json */,
F0442A1C25C7507500D998A5 /* vendor */,
);
name = Resources;
path = "TabFS Extension";
sourceTree = SOURCE_ROOT;
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
F028D2B025D0B7370095C2D5 /* TabFSService */ = {
isa = PBXNativeTarget;
buildConfigurationList = F028D2C025D0B7370095C2D5 /* Build configuration list for PBXNativeTarget "TabFSService" */;
buildPhases = (
F028D2AD25D0B7370095C2D5 /* Sources */,
F028D2AE25D0B7370095C2D5 /* Frameworks */,
F028D2AF25D0B7370095C2D5 /* Resources */,
F028D30E25D17BD20095C2D5 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
F028D33825D17D100095C2D5 /* PBXTargetDependency */,
);
name = TabFSService;
productName = TabFSService;
productReference = F028D2B125D0B7370095C2D5 /* TabFSService.xpc */;
productType = "com.apple.product-type.xpc-service";
};
F028D2FD25D17B080095C2D5 /* TabFSServer */ = {
isa = PBXNativeTarget;
buildConfigurationList = F028D30425D17B090095C2D5 /* Build configuration list for PBXNativeTarget "TabFSServer" */;
buildPhases = (
F028D2FA25D17B080095C2D5 /* Sources */,
F028D2FB25D17B080095C2D5 /* Frameworks */,
F028D2FC25D17B080095C2D5 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = TabFSServer;
productName = TabFSServer;
productReference = F028D2FE25D17B080095C2D5 /* TabFSServer */;
productType = "com.apple.product-type.tool";
};
F04429F025C7507200D998A5 /* TabFS */ = {
isa = PBXNativeTarget;
buildConfigurationList = F0442A1525C7507400D998A5 /* Build configuration list for PBXNativeTarget "TabFS" */;
buildPhases = (
F04429ED25C7507200D998A5 /* Sources */,
F04429EE25C7507200D998A5 /* Frameworks */,
F04429EF25C7507200D998A5 /* Resources */,
F0442A1425C7507400D998A5 /* Embed App Extensions */,
);
buildRules = (
);
dependencies = (
F0442A0625C7507400D998A5 /* PBXTargetDependency */,
);
name = TabFS;
productName = TabFS;
productReference = F04429F125C7507200D998A5 /* TabFS.app */;
productType = "com.apple.product-type.application";
};
F0442A0225C7507400D998A5 /* TabFS Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = F0442A1125C7507400D998A5 /* Build configuration list for PBXNativeTarget "TabFS Extension" */;
buildPhases = (
F04429FF25C7507400D998A5 /* Sources */,
F0442A0025C7507400D998A5 /* Frameworks */,
F0442A0125C7507400D998A5 /* Resources */,
F028D2E525D106BB0095C2D5 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "TabFS Extension";
productName = "TabFS Extension";
productReference = F0442A0325C7507400D998A5 /* TabFS Extension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F04429E925C7507200D998A5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1210;
LastUpgradeCheck = 1210;
TargetAttributes = {
F028D2B025D0B7370095C2D5 = {
CreatedOnToolsVersion = 12.1;
};
F028D2FD25D17B080095C2D5 = {
CreatedOnToolsVersion = 12.1;
};
F04429F025C7507200D998A5 = {
CreatedOnToolsVersion = 12.1;
};
F0442A0225C7507400D998A5 = {
CreatedOnToolsVersion = 12.1;
};
};
};
buildConfigurationList = F04429EC25C7507200D998A5 /* Build configuration list for PBXProject "TabFS" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = F04429E825C7507200D998A5;
productRefGroup = F04429F225C7507200D998A5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
F04429F025C7507200D998A5 /* TabFS */,
F0442A0225C7507400D998A5 /* TabFS Extension */,
F028D2B025D0B7370095C2D5 /* TabFSService */,
F028D2FD25D17B080095C2D5 /* TabFSServer */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
F028D2AF25D0B7370095C2D5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F04429EF25C7507200D998A5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F04429FD25C7507400D998A5 /* Assets.xcassets in Resources */,
F04429F925C7507200D998A5 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0442A0125C7507400D998A5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F0442A2025C7507500D998A5 /* vendor in Resources */,
F0442A1E25C7507500D998A5 /* safari in Resources */,
F0442A1F25C7507500D998A5 /* manifest.json in Resources */,
F0442A1D25C7507500D998A5 /* background.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
F028D2AD25D0B7370095C2D5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F028D2B825D0B7370095C2D5 /* main.swift in Sources */,
F028D2B625D0B7370095C2D5 /* TabFSService.swift in Sources */,
F028D2D725D0B8500095C2D5 /* TabFSServiceProtocols.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F028D2FA25D17B080095C2D5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F028D30125D17B080095C2D5 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F04429ED25C7507200D998A5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F04429FB25C7507200D998A5 /* ViewController.swift in Sources */,
F04429F625C7507200D998A5 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F04429FF25C7507400D998A5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F028D2DE25D0B8590095C2D5 /* TabFSServiceProtocols.swift in Sources */,
F0442A0C25C7507400D998A5 /* SafariWebExtensionHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F028D33825D17D100095C2D5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F028D2FD25D17B080095C2D5 /* TabFSServer */;
targetProxy = F028D33725D17D100095C2D5 /* PBXContainerItemProxy */;
};
F0442A0625C7507400D998A5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F0442A0225C7507400D998A5 /* TabFS Extension */;
targetProxy = F0442A0525C7507400D998A5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
F04429F725C7507200D998A5 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
F04429F825C7507200D998A5 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
F028D2BE25D0B7370095C2D5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = TabFSService/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = com.rsnous.TabFSService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
SWIFT_VERSION = 4.2;
};
name = Debug;
};
F028D2BF25D0B7370095C2D5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = TabFSService/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = com.rsnous.TabFSService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
SWIFT_VERSION = 4.2;
};
name = Release;
};
F028D30225D17B080095C2D5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 75YA78K5AM;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
F028D30325D17B080095C2D5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 75YA78K5AM;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
F0442A0F25C7507400D998A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
F0442A1025C7507400D998A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
F0442A1225C7507400D998A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "TabFS Extension/TabFS_Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = "TabFS Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
PRODUCT_BUNDLE_IDENTIFIER = "com.rsnous.TabFS-Extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
F0442A1325C7507400D998A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "TabFS Extension/TabFS_Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = "TabFS Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
PRODUCT_BUNDLE_IDENTIFIER = "com.rsnous.TabFS-Extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
F0442A1625C7507400D998A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = TabFS/TabFS.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = TabFS/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
PRODUCT_BUNDLE_IDENTIFIER = com.rsnous.TabFS;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
F0442A1725C7507400D998A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = TabFS/TabFS.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = TabFS/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
PRODUCT_BUNDLE_IDENTIFIER = com.rsnous.TabFS;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
F028D2C025D0B7370095C2D5 /* Build configuration list for PBXNativeTarget "TabFSService" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F028D2BE25D0B7370095C2D5 /* Debug */,
F028D2BF25D0B7370095C2D5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F028D30425D17B090095C2D5 /* Build configuration list for PBXNativeTarget "TabFSServer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F028D30225D17B080095C2D5 /* Debug */,
F028D30325D17B080095C2D5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F04429EC25C7507200D998A5 /* Build configuration list for PBXProject "TabFS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F0442A0F25C7507400D998A5 /* Debug */,
F0442A1025C7507400D998A5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F0442A1125C7507400D998A5 /* Build configuration list for PBXNativeTarget "TabFS Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F0442A1225C7507400D998A5 /* Debug */,
F0442A1325C7507400D998A5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F0442A1525C7507400D998A5 /* Build configuration list for PBXNativeTarget "TabFS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F0442A1625C7507400D998A5 /* Debug */,
F0442A1725C7507400D998A5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F04429E925C7507200D998A5 /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "E800B344-2058-48B2-A3D6-C86FFE39A01A"
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "62A8B265-14D3-4F90-9C2B-6F38280A1C0A"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TabFS Extension/SafariWebExtensionHandler.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "15"
endingLineNumber = "15"
landmarkName = "beginRequest(with:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "171B952C-1DD2-4555-B565-AF63FA641791"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TabFS Extension/FSProcessManager.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "26"
endingLineNumber = "26"
landmarkName = "start()"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>TabFS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>TabFSServer.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>TabFSService.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,21 @@
//
// AppDelegate.swift
// TabFS
//
// Created by Omar Rizwan on 1/31/21.
//
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}

View file

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17156"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="TabFS" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="TabFS" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About TabFS" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Hide TabFS" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit TabFS" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="TabFS Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="TabFS" customModuleProvider="target"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="76" y="-134"/>
</scene>
<!--Window Controller-->
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController showSeguePresentationStyle="single" id="B8D-0N-5wS" sceneMemberID="viewController">
<window key="window" title="App Name" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenNone="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
</connections>
</window>
<connections>
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="250"/>
</scene>
<!--View Controller-->
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="TabFS" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="m2S-Jp-Qdl">
<rect key="frame" x="0.0" y="0.0" width="480" height="407"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="centerX" spacing="42" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZLV-xE-AGT">
<rect key="frame" x="0.0" y="34" width="480" height="328"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="FWV-e2-WQh" userLabel="IconView">
<rect key="frame" x="176" y="137" width="128" height="191"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" image="AppIcon" id="Hhb-TZ-Dhg"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="EB0-ac-UZR">
<rect key="frame" x="38" y="63" width="404" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="400" id="pZE-0p-Ce8"/>
</constraints>
<textFieldCell key="cell" alignment="center" title="App Name's extension is currently off. You can turn it on in Safari Extensions preferences." id="S7v-7o-3vW">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ooh-eV-eLQ">
<rect key="frame" x="79" y="-7" width="322" height="32"/>
<buttonCell key="cell" type="push" title="Quit and Open Safari Extensions Preferences…" alternateTitle="Install" bezelStyle="rounded" alignment="center" lineBreakMode="truncatingMiddle" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Srx-0j-A4D">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
<connections>
<action selector="openSafariExtensionPreferences:" target="XfG-lQ-9wD" id="vKk-Xb-MPh"/>
</connections>
</buttonCell>
</button>
</subviews>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="ZLV-xE-AGT" secondAttribute="trailing" id="7aD-Ze-9ed"/>
<constraint firstItem="ZLV-xE-AGT" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="45" id="AJ3-sx-ZQx"/>
<constraint firstAttribute="bottom" secondItem="ZLV-xE-AGT" secondAttribute="bottom" constant="34" id="KVY-ss-lTJ"/>
<constraint firstItem="ZLV-xE-AGT" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="mT6-ee-vkp"/>
</constraints>
</view>
<connections>
<outlet property="appNameLabel" destination="EB0-ac-UZR" id="SDO-j1-PQa"/>
</connections>
</viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="655"/>
</scene>
</scenes>
<resources>
<image name="AppIcon" width="128" height="128"/>
</resources>
</document>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,50 @@
//
// ViewController.swift
// TabFS
//
// Created by Omar Rizwan on 1/31/21.
//
import Cocoa
import SafariServices.SFSafariApplication
import SafariServices.SFSafariExtensionManager
let appName = "TabFS"
let extensionBundleIdentifier = "com.rsnous.TabFS-Extension"
class ViewController: NSViewController {
@IBOutlet var appNameLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
self.appNameLabel.stringValue = appName
SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { (state, error) in
guard let state = state, error == nil else {
// Insert code to inform the user that something went wrong.
return
}
DispatchQueue.main.async {
if (state.isEnabled) {
self.appNameLabel.stringValue = "\(appName)'s extension is currently on."
} else {
self.appNameLabel.stringValue = "\(appName)'s extension is currently off. You can turn it on in Safari Extensions preferences."
}
}
}
}
@IBAction func openSafariExtensionPreferences(_ sender: AnyObject?) {
SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in
guard error == nil else {
// Insert code to inform the user that something went wrong.
return
}
DispatchQueue.main.async {
NSApplication.shared.terminate(nil)
}
}
}
}

View file

@ -0,0 +1,114 @@
//
// main.swift
// TabFSServer
//
// Created by Omar Rizwan on 2/8/21.
//
import Foundation
import Network
import os.log
class TabFSServer {
var fs: Process!
var fsInput: FileHandle!
var fsOutput: FileHandle!
func startFs() {
let fileURL = URL(fileURLWithPath: #filePath)
let repoURL = fileURL.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent()
fs = Process()
fs.executableURL = repoURL.appendingPathComponent("fs").appendingPathComponent("tabfs")
fs.currentDirectoryURL = fs.executableURL?.deletingLastPathComponent()
fs.arguments = []
let inputPipe = Pipe(), outputPipe = Pipe()
fs.standardInput = inputPipe
fs.standardOutput = outputPipe
fsInput = inputPipe.fileHandleForWriting
fsOutput = outputPipe.fileHandleForReading
try! fs.run()
}
var ws: NWListener!
func startWs() {
// TODO: randomly generate port and report back to caller?
let port = NWEndpoint.Port(rawValue: 9991)!
let parameters = NWParameters(tls: nil)
parameters.allowLocalEndpointReuse = true
parameters.includePeerToPeer = true
// for security ? so people outside your computer can't hijack TabFS at least
parameters.requiredInterfaceType = .loopback
let opts = NWProtocolWebSocket.Options()
opts.autoReplyPing = true
parameters.defaultProtocolStack.applicationProtocols.insert(opts, at: 0)
ws = try! NWListener(using: parameters, on: port)
ws.start(queue: .main)
}
init() {
startFs()
startWs()
var handleRequest: ((_ req: Data) -> Void)?
ws.newConnectionHandler = { conn in
conn.start(queue: .main)
handleRequest = { req in
let metaData = NWProtocolWebSocket.Metadata(opcode: .text)
let context = NWConnection.ContentContext(identifier: "context", metadata: [metaData])
conn.send(content: req, contentContext: context, completion: .contentProcessed({ err in
if err != nil {
os_log(.default, "req %{public}@ error: %{public}@", String(data: req, encoding: .utf8)!, err!.debugDescription as CVarArg)
// FIXME: ERROR
}
}))
}
func read() {
conn.receiveMessage { (resp, context, isComplete, err) in
guard let resp = resp else {
if let err = err {
os_log(.default, "resp error: %{public}@", err.debugDescription as CVarArg)
}
return
}
// Send the response back to tabfs.c.
self.fsInput.write(withUnsafeBytes(of: UInt32(resp.count)) { Data($0) })
self.fsInput.write(resp)
read()
}
}
read()
}
DispatchQueue.global(qos: .default).async {
while true {
// Blocking read from the tabfs process.
let length = self.fsOutput.readData(ofLength: 4).withUnsafeBytes { $0.load(as: UInt32.self) }
let req = self.fsOutput.readData(ofLength: Int(length))
if let handleRequest = handleRequest {
// Send the request over the WebSocket connection to background.js in browser.
handleRequest(req)
} else {
// FIXME: ERROR
}
}
}
print("OK")
}
}
let server = TabFSServer()
dispatchMain()

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>TabFSService</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>XPCService</key>
<dict>
<key>ServiceType</key>
<string>Application</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,58 @@
//
// TabFSService.swift
// TabFSService
//
// Created by Omar Rizwan on 2/7/21.
//
import Foundation
import Network
import os.log
class TabFSService: NSObject, TabFSServiceProtocol {
func start(withReply reply: @escaping () -> Void) {
// This XPC call is enough to just force the XPC service to be started.
// kill old copies of TabFSServer
let killall = Process()
killall.launchPath = "/usr/bin/killall"
killall.arguments = ["TabFSServer"]
killall.launch()
killall.waitUntilExit()
// spin until old TabFSServer (if any) is gone
while true {
let pgrep = Process()
pgrep.launchPath = "/usr/bin/pgrep"
pgrep.arguments = ["TabFSServer"]
pgrep.launch()
pgrep.waitUntilExit()
if pgrep.terminationStatus != 0 { break }
Thread.sleep(forTimeInterval: 0.01)
}
let server = Process()
let serverOutput = Pipe()
server.executableURL = Bundle.main.url(forResource: "TabFSServer", withExtension: "")!
server.standardOutput = serverOutput
server.launch()
// FIXME: should we wait for some signal that the server is ready?
// right now, background.js will just periodically retry until it can connect.
// tell background.js to try to connect.
reply()
}
}
class TabFSServiceDelegate: NSObject, NSXPCListenerDelegate {
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
let exportedObject = TabFSService()
newConnection.exportedInterface = NSXPCInterface(with: TabFSServiceProtocol.self)
newConnection.exportedObject = exportedObject
newConnection.resume()
return true
}
}

View file

@ -0,0 +1,12 @@
//
// TabFSServiceProtocols.swift
// app-sandbox-xpc-test
//
// Created by Omar Rizwan on 2/7/21.
//
import Foundation
@objc public protocol TabFSServiceProtocol {
func start(withReply reply: @escaping () -> Void)
}

View file

@ -0,0 +1,15 @@
//
// main.m
// TabFSService
//
// Created by Omar Rizwan on 2/7/21.
//
import Foundation
ProcessInfo.processInfo.disableAutomaticTermination("ok")
let delegate = TabFSServiceDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()