bitwarden-estensione-browser/src/safari/safari/SafariWebExtensionHandler.s...

118 lines
3.8 KiB
Swift

import SafariServices
import os.log
let SFExtensionMessageKey = "message"
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
let item = context.inputItems[0] as! NSExtensionItem
let message = item.userInfo?[SFExtensionMessageKey] as AnyObject?
os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg)
let response = NSExtensionItem()
guard let command = message?["command"] as? String else {
return
}
switch (command) {
case "readFromClipboard":
let pasteboard = NSPasteboard.general
response.userInfo = [ SFExtensionMessageKey: pasteboard.pasteboardItems?.first?.string(forType: .string) as Any ]
break
case "copyToClipboard":
guard let msg = message?["data"] as? String else {
return
}
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(msg, forType: .string)
case "showPopover":
SFSafariApplication.getActiveWindow { win in
win?.getToolbarItem(completionHandler: { item in
item?.showPopover()
})
}
break
case "downloadFile":
guard let jsonData = message?["data"] as? String else {
return
}
guard let dlMsg: DownloadFileMessage = jsonDeserialize(json: jsonData) else {
return
}
var blobData: Data?
if dlMsg.blobOptions?.type == "text/plain" {
blobData = dlMsg.blobData?.data(using: .utf8)
} else if let blob = dlMsg.blobData {
blobData = Data(base64Encoded: blob)
}
guard let data = blobData else {
return
}
let panel = NSSavePanel()
panel.isFloatingPanel = true
panel.canCreateDirectories = true
panel.nameFieldStringValue = dlMsg.fileName
panel.begin { response in
if response == NSApplication.ModalResponse.OK {
if let url = panel.url {
do {
let fileManager = FileManager.default
if !fileManager.fileExists(atPath: url.absoluteString) {
fileManager.createFile(atPath: url.absoluteString, contents: Data(),
attributes: nil)
}
try data.write(to: url)
} catch {
print(error)
NSLog("ERROR in downloadFile, \(error)")
}
}
}
}
break
default:
return
}
context.completeRequest(returningItems: [response], completionHandler: nil)
}
}
func jsonSerialize<T: Encodable>(obj: T?) -> String? {
let encoder = JSONEncoder()
do {
let data = try encoder.encode(obj)
return String(data: data, encoding: .utf8) ?? "null"
} catch _ {
return "null"
}
}
func jsonDeserialize<T: Decodable>(json: String?) -> T? {
if json == nil {
return nil
}
let decoder = JSONDecoder()
do {
let obj = try decoder.decode(T.self, from: json!.data(using: .utf8)!)
return obj
} catch _ {
return nil
}
}
class DownloadFileMessage: Decodable, Encodable {
var fileName: String
var blobData: String?
var blobOptions: DownloadFileMessageBlobOptions?
}
class DownloadFileMessageBlobOptions: Decodable, Encodable {
var type: String?
}