mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-12 10:14:10 +01:00
Simplify beginRequest
Signed-off-by: Mikaël Barbero <mikael.barbero@eclipse-foundation.org>
This commit is contained in:
parent
7abbe0dafd
commit
45b6e6c6c2
@ -26,147 +26,18 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
|
||||
|
||||
switch (command) {
|
||||
case "readFromClipboard":
|
||||
let pasteboard = NSPasteboard.general
|
||||
response.userInfo = [ SFExtensionMessageKey: pasteboard.pasteboardItems?.first?.string(forType: .string) as Any ]
|
||||
break
|
||||
handleReadFromClipboard(&response)
|
||||
case "copyToClipboard":
|
||||
guard let msg = message?["data"] as? String else {
|
||||
return
|
||||
}
|
||||
let pasteboard = NSPasteboard.general
|
||||
pasteboard.clearContents()
|
||||
pasteboard.setString(msg, forType: .string)
|
||||
handleCopyToClipboard(message)
|
||||
case "showPopover":
|
||||
SFSafariApplication.getActiveWindow { win in
|
||||
win?.getToolbarItem(completionHandler: { item in
|
||||
item?.showPopover()
|
||||
})
|
||||
}
|
||||
break
|
||||
handleShowPopover()
|
||||
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.canCreateDirectories = true
|
||||
panel.nameFieldStringValue = dlMsg.fileName
|
||||
let response = panel.runModal();
|
||||
|
||||
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
|
||||
handleDownloadFile(message)
|
||||
case "sleep":
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
|
||||
context.completeRequest(returningItems: [response], completionHandler: nil)
|
||||
}
|
||||
handleSleep(context, response)
|
||||
return
|
||||
case "biometricUnlock":
|
||||
|
||||
var error: NSError?
|
||||
let laContext = LAContext()
|
||||
|
||||
laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
|
||||
|
||||
if let e = error, e.code != kLAErrorBiometryLockout {
|
||||
response.userInfo = [
|
||||
SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "not supported",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
],
|
||||
],
|
||||
]
|
||||
break
|
||||
}
|
||||
|
||||
guard let accessControl = SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.privateKeyUsage, .userPresence], nil) else {
|
||||
response.userInfo = [
|
||||
SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "not supported",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
],
|
||||
],
|
||||
]
|
||||
break
|
||||
}
|
||||
laContext.evaluateAccessControl(accessControl, operation: .useKeySign, localizedReason: "Bitwarden Safari Extension") { (success, error) in
|
||||
if success {
|
||||
guard let userId = message?["userId"] as? String else {
|
||||
return
|
||||
}
|
||||
let passwordName = userId + "_user_biometric"
|
||||
var passwordLength: UInt32 = 0
|
||||
var passwordPtr: UnsafeMutableRawPointer? = nil
|
||||
|
||||
var status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(passwordName.utf8.count), passwordName, &passwordLength, &passwordPtr, nil)
|
||||
if status != errSecSuccess {
|
||||
let fallbackName = "key"
|
||||
status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(fallbackName.utf8.count), fallbackName, &passwordLength, &passwordPtr, nil)
|
||||
}
|
||||
|
||||
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3473)
|
||||
if status != errSecSuccess {
|
||||
let secondaryFallbackName = "_masterkey_biometric"
|
||||
status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(secondaryFallbackName.utf8.count), secondaryFallbackName, &passwordLength, &passwordPtr, nil)
|
||||
}
|
||||
|
||||
if status == errSecSuccess {
|
||||
let result = NSString(bytes: passwordPtr!, length: Int(passwordLength), encoding: String.Encoding.utf8.rawValue) as String?
|
||||
SecKeychainItemFreeContent(nil, passwordPtr)
|
||||
|
||||
response.userInfo = [ SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "unlocked",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
"userKeyB64": result!.replacingOccurrences(of: "\"", with: ""),
|
||||
],
|
||||
]]
|
||||
} else {
|
||||
response.userInfo = [
|
||||
SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "not enabled",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
],
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
context.completeRequest(returningItems: [response], completionHandler: nil)
|
||||
}
|
||||
|
||||
handleBiometricUnlock(message, context, &response)
|
||||
return
|
||||
default:
|
||||
return
|
||||
@ -177,6 +48,156 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
|
||||
|
||||
}
|
||||
|
||||
func handleReadFromClipboard(_ response: inout NSExtensionItem) {
|
||||
let pasteboard = NSPasteboard.general
|
||||
response.userInfo = [ SFExtensionMessageKey: pasteboard.pasteboardItems?.first?.string(forType: .string) as Any ]
|
||||
}
|
||||
|
||||
func handleCopyToClipboard(_ message: [String: Any]?) {
|
||||
guard let msg = message?["data"] as? String else {
|
||||
return
|
||||
}
|
||||
let pasteboard = NSPasteboard.general
|
||||
pasteboard.clearContents()
|
||||
pasteboard.setString(msg, forType: .string)
|
||||
}
|
||||
|
||||
func handleShowPopover() {
|
||||
SFSafariApplication.getActiveWindow { win in
|
||||
win?.getToolbarItem(completionHandler: { item in
|
||||
item?.showPopover()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func handleDownloadFile(_ message: [String: Any]?) {
|
||||
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.canCreateDirectories = true
|
||||
panel.nameFieldStringValue = dlMsg.fileName
|
||||
let response = panel.runModal();
|
||||
|
||||
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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleSleep(_ context: NSExtensionContext, _ response: NSExtensionItem) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
|
||||
context.completeRequest(returningItems: [response], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func handleBiometricUnlock(_ message: [String: Any]?, _ context: NSExtensionContext, _ response: inout NSExtensionItem) {
|
||||
var error: NSError?
|
||||
let laContext = LAContext()
|
||||
|
||||
laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
|
||||
|
||||
if let e = error, e.code != kLAErrorBiometryLockout {
|
||||
response.userInfo = [
|
||||
SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "not supported",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
],
|
||||
],
|
||||
]
|
||||
break
|
||||
}
|
||||
|
||||
guard let accessControl = SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.privateKeyUsage, .userPresence], nil) else {
|
||||
response.userInfo = [
|
||||
SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "not supported",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
],
|
||||
],
|
||||
]
|
||||
break
|
||||
}
|
||||
laContext.evaluateAccessControl(accessControl, operation: .useKeySign, localizedReason: "Bitwarden Safari Extension") { (success, error) in
|
||||
if success {
|
||||
guard let userId = message?["userId"] as? String else {
|
||||
return
|
||||
}
|
||||
let passwordName = userId + "_user_biometric"
|
||||
var passwordLength: UInt32 = 0
|
||||
var passwordPtr: UnsafeMutableRawPointer? = nil
|
||||
|
||||
var status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(passwordName.utf8.count), passwordName, &passwordLength, &passwordPtr, nil)
|
||||
if status != errSecSuccess {
|
||||
let fallbackName = "key"
|
||||
status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(fallbackName.utf8.count), fallbackName, &passwordLength, &passwordPtr, nil)
|
||||
}
|
||||
|
||||
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3473)
|
||||
if status != errSecSuccess {
|
||||
let secondaryFallbackName = "_masterkey_biometric"
|
||||
status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(secondaryFallbackName.utf8.count), secondaryFallbackName, &passwordLength, &passwordPtr, nil)
|
||||
}
|
||||
|
||||
if status == errSecSuccess {
|
||||
let result = NSString(bytes: passwordPtr!, length: Int(passwordLength), encoding: String.Encoding.utf8.rawValue) as String?
|
||||
SecKeychainItemFreeContent(nil, passwordPtr)
|
||||
|
||||
response.userInfo = [ SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "unlocked",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
"userKeyB64": result!.replacingOccurrences(of: "\"", with: ""),
|
||||
],
|
||||
]]
|
||||
} else {
|
||||
response.userInfo = [
|
||||
SFExtensionMessageKey: [
|
||||
"message": [
|
||||
"command": "biometricUnlock",
|
||||
"response": "not enabled",
|
||||
"timestamp": Int64(NSDate().timeIntervalSince1970 * 1000),
|
||||
],
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
context.completeRequest(returningItems: [response], completionHandler: nil)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func jsonSerialize<T: Encodable>(obj: T?) -> String? {
|
||||
let encoder = JSONEncoder()
|
||||
do {
|
||||
|
Loading…
Reference in New Issue
Block a user