diff --git a/.gitignore b/.gitignore index c3ee4a4ac..a7a1a421e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store .idea *.swp @@ -11,3 +12,4 @@ .xz node_modules test-results +xcuserdata/ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser Extension/Info.plist b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser Extension/Info.plist new file mode 100644 index 000000000..9ee504dc5 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser Extension/Info.plist @@ -0,0 +1,13 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.Safari.web-extension + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler + + + diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser Extension/SafariWebExtensionHandler.swift b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser Extension/SafariWebExtensionHandler.swift new file mode 100644 index 000000000..3f5095806 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser Extension/SafariWebExtensionHandler.swift @@ -0,0 +1,42 @@ +// +// SafariWebExtensionHandler.swift +// KeePassXC-Browser Extension +// +// Created by varjolintu on 12.12.2025. +// + +import SafariServices +import os.log + +class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { + + func beginRequest(with context: NSExtensionContext) { + let request = context.inputItems.first as? NSExtensionItem + + let profile: UUID? + if #available(iOS 17.0, macOS 14.0, *) { + profile = request?.userInfo?[SFExtensionProfileKey] as? UUID + } else { + profile = request?.userInfo?["profile"] as? UUID + } + + let message: Any? + if #available(iOS 15.0, macOS 11.0, *) { + message = request?.userInfo?[SFExtensionMessageKey] + } else { + message = request?.userInfo?["message"] + } + + os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@ (profile: %@)", String(describing: message), profile?.uuidString ?? "none") + + let response = NSExtensionItem() + if #available(iOS 15.0, macOS 11.0, *) { + response.userInfo = [ SFExtensionMessageKey: [ "echo": message ] ] + } else { + response.userInfo = [ "message": [ "echo": message ] ] + } + + context.completeRequest(returningItems: [ response ], completionHandler: nil) + } + +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser.xcodeproj/project.pbxproj b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d5b3dfc98 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser.xcodeproj/project.pbxproj @@ -0,0 +1,645 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 6325CAC52EEC98E200E3BCF2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6325CAC42EEC98E200E3BCF2 /* AppDelegate.swift */; }; + 6325CAC92EEC98E200E3BCF2 /* Main.html in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAC72EEC98E200E3BCF2 /* Main.html */; }; + 6325CACB2EEC98E200E3BCF2 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 6325CACA2EEC98E200E3BCF2 /* Icon.png */; }; + 6325CACD2EEC98E200E3BCF2 /* Style.css in Resources */ = {isa = PBXBuildFile; fileRef = 6325CACC2EEC98E200E3BCF2 /* Style.css */; }; + 6325CACF2EEC98E200E3BCF2 /* Script.js in Resources */ = {isa = PBXBuildFile; fileRef = 6325CACE2EEC98E200E3BCF2 /* Script.js */; }; + 6325CAD12EEC98E200E3BCF2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6325CAD02EEC98E200E3BCF2 /* ViewController.swift */; }; + 6325CAD42EEC98E200E3BCF2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAD22EEC98E200E3BCF2 /* Main.storyboard */; }; + 6325CAD62EEC98E300E3BCF2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAD52EEC98E300E3BCF2 /* Assets.xcassets */; }; + 6325CADD2EEC98E300E3BCF2 /* KeePassXC-Browser Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 6325CADC2EEC98E300E3BCF2 /* KeePassXC-Browser Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 6325CAE22EEC98E300E3BCF2 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6325CAE12EEC98E300E3BCF2 /* SafariWebExtensionHandler.swift */; }; + 6325CAFB2EEC98E300E3BCF2 /* background in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAEE2EEC98E300E3BCF2 /* background */; }; + 6325CAFC2EEC98E300E3BCF2 /* offscreen in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAEF2EEC98E300E3BCF2 /* offscreen */; }; + 6325CAFD2EEC98E300E3BCF2 /* options in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF02EEC98E300E3BCF2 /* options */; }; + 6325CAFE2EEC98E300E3BCF2 /* bootstrap in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF12EEC98E300E3BCF2 /* bootstrap */; }; + 6325CAFF2EEC98E300E3BCF2 /* css in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF22EEC98E300E3BCF2 /* css */; }; + 6325CB002EEC98E300E3BCF2 /* content in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF32EEC98E300E3BCF2 /* content */; }; + 6325CB012EEC98E300E3BCF2 /* managed_storage.json in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF42EEC98E300E3BCF2 /* managed_storage.json */; }; + 6325CB022EEC98E300E3BCF2 /* common in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF52EEC98E300E3BCF2 /* common */; }; + 6325CB032EEC98E300E3BCF2 /* popups in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF62EEC98E300E3BCF2 /* popups */; }; + 6325CB042EEC98E300E3BCF2 /* icons in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF72EEC98E300E3BCF2 /* icons */; }; + 6325CB052EEC98E300E3BCF2 /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF82EEC98E300E3BCF2 /* manifest.json */; }; + 6325CB062EEC98E300E3BCF2 /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAF92EEC98E300E3BCF2 /* _locales */; }; + 6325CB072EEC98E300E3BCF2 /* fonts in Resources */ = {isa = PBXBuildFile; fileRef = 6325CAFA2EEC98E300E3BCF2 /* fonts */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 6325CADE2EEC98E300E3BCF2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6325CAB92EEC98E200E3BCF2 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6325CADB2EEC98E300E3BCF2; + remoteInfo = "KeePassXC-Browser Extension"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 6325CAE92EEC98E300E3BCF2 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 6325CADD2EEC98E300E3BCF2 /* KeePassXC-Browser Extension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 6325CAC12EEC98E200E3BCF2 /* KeePassXC-Browser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "KeePassXC-Browser.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 6325CAC42EEC98E200E3BCF2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 6325CAC82EEC98E200E3BCF2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = Base.lproj/Main.html; sourceTree = ""; }; + 6325CACA2EEC98E200E3BCF2 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; + 6325CACC2EEC98E200E3BCF2 /* Style.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = Style.css; sourceTree = ""; }; + 6325CACE2EEC98E200E3BCF2 /* Script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = Script.js; sourceTree = ""; }; + 6325CAD02EEC98E200E3BCF2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 6325CAD32EEC98E200E3BCF2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 6325CAD52EEC98E300E3BCF2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 6325CAD72EEC98E300E3BCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6325CADC2EEC98E300E3BCF2 /* KeePassXC-Browser Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "KeePassXC-Browser Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 6325CAE12EEC98E300E3BCF2 /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = ""; }; + 6325CAE32EEC98E300E3BCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6325CAEE2EEC98E300E3BCF2 /* background */ = {isa = PBXFileReference; lastKnownFileType = folder; name = background; path = "../../../keepassxc-browser/background"; sourceTree = ""; }; + 6325CAEF2EEC98E300E3BCF2 /* offscreen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = offscreen; path = "../../../keepassxc-browser/offscreen"; sourceTree = ""; }; + 6325CAF02EEC98E300E3BCF2 /* options */ = {isa = PBXFileReference; lastKnownFileType = folder; name = options; path = "../../../keepassxc-browser/options"; sourceTree = ""; }; + 6325CAF12EEC98E300E3BCF2 /* bootstrap */ = {isa = PBXFileReference; lastKnownFileType = folder; name = bootstrap; path = "../../../keepassxc-browser/bootstrap"; sourceTree = ""; }; + 6325CAF22EEC98E300E3BCF2 /* css */ = {isa = PBXFileReference; lastKnownFileType = folder; name = css; path = "../../../keepassxc-browser/css"; sourceTree = ""; }; + 6325CAF32EEC98E300E3BCF2 /* content */ = {isa = PBXFileReference; lastKnownFileType = folder; name = content; path = "../../../keepassxc-browser/content"; sourceTree = ""; }; + 6325CAF42EEC98E300E3BCF2 /* managed_storage.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = managed_storage.json; path = "../../../keepassxc-browser/managed_storage.json"; sourceTree = ""; }; + 6325CAF52EEC98E300E3BCF2 /* common */ = {isa = PBXFileReference; lastKnownFileType = folder; name = common; path = "../../../keepassxc-browser/common"; sourceTree = ""; }; + 6325CAF62EEC98E300E3BCF2 /* popups */ = {isa = PBXFileReference; lastKnownFileType = folder; name = popups; path = "../../../keepassxc-browser/popups"; sourceTree = ""; }; + 6325CAF72EEC98E300E3BCF2 /* icons */ = {isa = PBXFileReference; lastKnownFileType = folder; name = icons; path = "../../../keepassxc-browser/icons"; sourceTree = ""; }; + 6325CAF82EEC98E300E3BCF2 /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = manifest.json; path = "../../../keepassxc-browser/manifest.json"; sourceTree = ""; }; + 6325CAF92EEC98E300E3BCF2 /* _locales */ = {isa = PBXFileReference; lastKnownFileType = folder; name = _locales; path = "../../../keepassxc-browser/_locales"; sourceTree = ""; }; + 6325CAFA2EEC98E300E3BCF2 /* fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; name = fonts; path = "../../../keepassxc-browser/fonts"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6325CABE2EEC98E200E3BCF2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6325CAD92EEC98E300E3BCF2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6325CAB82EEC98E200E3BCF2 = { + isa = PBXGroup; + children = ( + 6325CAC32EEC98E200E3BCF2 /* KeePassXC-Browser */, + 6325CAE02EEC98E300E3BCF2 /* KeePassXC-Browser Extension */, + 6325CAC22EEC98E200E3BCF2 /* Products */, + ); + sourceTree = ""; + }; + 6325CAC22EEC98E200E3BCF2 /* Products */ = { + isa = PBXGroup; + children = ( + 6325CAC12EEC98E200E3BCF2 /* KeePassXC-Browser.app */, + 6325CADC2EEC98E300E3BCF2 /* KeePassXC-Browser Extension.appex */, + ); + name = Products; + sourceTree = ""; + }; + 6325CAC32EEC98E200E3BCF2 /* KeePassXC-Browser */ = { + isa = PBXGroup; + children = ( + 6325CAC42EEC98E200E3BCF2 /* AppDelegate.swift */, + 6325CAD02EEC98E200E3BCF2 /* ViewController.swift */, + 6325CAD22EEC98E200E3BCF2 /* Main.storyboard */, + 6325CAD52EEC98E300E3BCF2 /* Assets.xcassets */, + 6325CAD72EEC98E300E3BCF2 /* Info.plist */, + 6325CAC62EEC98E200E3BCF2 /* Resources */, + ); + path = "KeePassXC-Browser"; + sourceTree = ""; + }; + 6325CAC62EEC98E200E3BCF2 /* Resources */ = { + isa = PBXGroup; + children = ( + 6325CAC72EEC98E200E3BCF2 /* Main.html */, + 6325CACA2EEC98E200E3BCF2 /* Icon.png */, + 6325CACC2EEC98E200E3BCF2 /* Style.css */, + 6325CACE2EEC98E200E3BCF2 /* Script.js */, + ); + path = Resources; + sourceTree = ""; + }; + 6325CAE02EEC98E300E3BCF2 /* KeePassXC-Browser Extension */ = { + isa = PBXGroup; + children = ( + 6325CAED2EEC98E300E3BCF2 /* Resources */, + 6325CAE12EEC98E300E3BCF2 /* SafariWebExtensionHandler.swift */, + 6325CAE32EEC98E300E3BCF2 /* Info.plist */, + ); + path = "KeePassXC-Browser Extension"; + sourceTree = ""; + }; + 6325CAED2EEC98E300E3BCF2 /* Resources */ = { + isa = PBXGroup; + children = ( + 6325CAEE2EEC98E300E3BCF2 /* background */, + 6325CAEF2EEC98E300E3BCF2 /* offscreen */, + 6325CAF02EEC98E300E3BCF2 /* options */, + 6325CAF12EEC98E300E3BCF2 /* bootstrap */, + 6325CAF22EEC98E300E3BCF2 /* css */, + 6325CAF32EEC98E300E3BCF2 /* content */, + 6325CAF42EEC98E300E3BCF2 /* managed_storage.json */, + 6325CAF52EEC98E300E3BCF2 /* common */, + 6325CAF62EEC98E300E3BCF2 /* popups */, + 6325CAF72EEC98E300E3BCF2 /* icons */, + 6325CAF82EEC98E300E3BCF2 /* manifest.json */, + 6325CAF92EEC98E300E3BCF2 /* _locales */, + 6325CAFA2EEC98E300E3BCF2 /* fonts */, + ); + name = Resources; + path = "KeePassXC-Browser Extension"; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6325CAC02EEC98E200E3BCF2 /* KeePassXC-Browser */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6325CAEA2EEC98E300E3BCF2 /* Build configuration list for PBXNativeTarget "KeePassXC-Browser" */; + buildPhases = ( + 6325CABD2EEC98E200E3BCF2 /* Sources */, + 6325CABE2EEC98E200E3BCF2 /* Frameworks */, + 6325CABF2EEC98E200E3BCF2 /* Resources */, + 6325CAE92EEC98E300E3BCF2 /* Embed Foundation Extensions */, + ); + buildRules = ( + ); + dependencies = ( + 6325CADF2EEC98E300E3BCF2 /* PBXTargetDependency */, + ); + name = "KeePassXC-Browser"; + packageProductDependencies = ( + ); + productName = "KeePassXC-Browser"; + productReference = 6325CAC12EEC98E200E3BCF2 /* KeePassXC-Browser.app */; + productType = "com.apple.product-type.application"; + }; + 6325CADB2EEC98E300E3BCF2 /* KeePassXC-Browser Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6325CAE62EEC98E300E3BCF2 /* Build configuration list for PBXNativeTarget "KeePassXC-Browser Extension" */; + buildPhases = ( + 6325CAD82EEC98E300E3BCF2 /* Sources */, + 6325CAD92EEC98E300E3BCF2 /* Frameworks */, + 6325CADA2EEC98E300E3BCF2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "KeePassXC-Browser Extension"; + packageProductDependencies = ( + ); + productName = "KeePassXC-Browser Extension"; + productReference = 6325CADC2EEC98E300E3BCF2 /* KeePassXC-Browser Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 6325CAB92EEC98E200E3BCF2 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 2610; + LastUpgradeCheck = 2610; + TargetAttributes = { + 6325CAC02EEC98E200E3BCF2 = { + CreatedOnToolsVersion = 26.1.1; + }; + 6325CADB2EEC98E300E3BCF2 = { + CreatedOnToolsVersion = 26.1.1; + }; + }; + }; + buildConfigurationList = 6325CABC2EEC98E200E3BCF2 /* Build configuration list for PBXProject "KeePassXC-Browser" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 6325CAB82EEC98E200E3BCF2; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 6325CAC22EEC98E200E3BCF2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6325CAC02EEC98E200E3BCF2 /* KeePassXC-Browser */, + 6325CADB2EEC98E300E3BCF2 /* KeePassXC-Browser Extension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 6325CABF2EEC98E200E3BCF2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6325CACB2EEC98E200E3BCF2 /* Icon.png in Resources */, + 6325CAD42EEC98E200E3BCF2 /* Main.storyboard in Resources */, + 6325CACF2EEC98E200E3BCF2 /* Script.js in Resources */, + 6325CAC92EEC98E200E3BCF2 /* Main.html in Resources */, + 6325CAD62EEC98E300E3BCF2 /* Assets.xcassets in Resources */, + 6325CACD2EEC98E200E3BCF2 /* Style.css in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6325CADA2EEC98E300E3BCF2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6325CB002EEC98E300E3BCF2 /* content in Resources */, + 6325CB072EEC98E300E3BCF2 /* fonts in Resources */, + 6325CAFF2EEC98E300E3BCF2 /* css in Resources */, + 6325CAFD2EEC98E300E3BCF2 /* options in Resources */, + 6325CB042EEC98E300E3BCF2 /* icons in Resources */, + 6325CAFC2EEC98E300E3BCF2 /* offscreen in Resources */, + 6325CB052EEC98E300E3BCF2 /* manifest.json in Resources */, + 6325CB062EEC98E300E3BCF2 /* _locales in Resources */, + 6325CAFB2EEC98E300E3BCF2 /* background in Resources */, + 6325CB032EEC98E300E3BCF2 /* popups in Resources */, + 6325CB012EEC98E300E3BCF2 /* managed_storage.json in Resources */, + 6325CAFE2EEC98E300E3BCF2 /* bootstrap in Resources */, + 6325CB022EEC98E300E3BCF2 /* common in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6325CABD2EEC98E200E3BCF2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6325CAD12EEC98E200E3BCF2 /* ViewController.swift in Sources */, + 6325CAC52EEC98E200E3BCF2 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6325CAD82EEC98E300E3BCF2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6325CAE22EEC98E300E3BCF2 /* SafariWebExtensionHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 6325CADF2EEC98E300E3BCF2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6325CADB2EEC98E300E3BCF2 /* KeePassXC-Browser Extension */; + targetProxy = 6325CADE2EEC98E300E3BCF2 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 6325CAC72EEC98E200E3BCF2 /* Main.html */ = { + isa = PBXVariantGroup; + children = ( + 6325CAC82EEC98E200E3BCF2 /* Base */, + ); + name = Main.html; + sourceTree = ""; + }; + 6325CAD22EEC98E200E3BCF2 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 6325CAD32EEC98E200E3BCF2 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 6325CAE42EEC98E300E3BCF2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + 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; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 26.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 6325CAE52EEC98E300E3BCF2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + 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; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 26.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 6325CAE72EEC98E300E3BCF2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "KeePassXC-Browser Extension/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "KeePassXC-Browser Extension"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.keepassxc.KeePassXC-Browser.Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 6325CAE82EEC98E300E3BCF2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "KeePassXC-Browser Extension/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "KeePassXC-Browser Extension"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.keepassxc.KeePassXC-Browser.Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 6325CAEB2EEC98E300E3BCF2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "KeePassXC-Browser/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "KeePassXC-Browser"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + "-framework", + WebKit, + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.keepassxc.KeePassXC-Browser"; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 6325CAEC2EEC98E300E3BCF2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "KeePassXC-Browser/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "KeePassXC-Browser"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + SafariServices, + "-framework", + WebKit, + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.keepassxc.KeePassXC-Browser"; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6325CABC2EEC98E200E3BCF2 /* Build configuration list for PBXProject "KeePassXC-Browser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6325CAE42EEC98E300E3BCF2 /* Debug */, + 6325CAE52EEC98E300E3BCF2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6325CAE62EEC98E300E3BCF2 /* Build configuration list for PBXNativeTarget "KeePassXC-Browser Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6325CAE72EEC98E300E3BCF2 /* Debug */, + 6325CAE82EEC98E300E3BCF2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6325CAEA2EEC98E300E3BCF2 /* Build configuration list for PBXNativeTarget "KeePassXC-Browser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6325CAEB2EEC98E300E3BCF2 /* Debug */, + 6325CAEC2EEC98E300E3BCF2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 6325CAB92EEC98E200E3BCF2 /* Project object */; +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/AppDelegate.swift b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/AppDelegate.swift new file mode 100644 index 000000000..bb709d8b6 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/AppDelegate.swift @@ -0,0 +1,21 @@ +// +// AppDelegate.swift +// KeePassXC-Browser +// +// Created by varjolintu on 12.12.2025. +// + +import Cocoa + +@main +class AppDelegate: NSObject, NSApplicationDelegate { + + func applicationDidFinishLaunching(_ notification: Notification) { + // Override point for customization after application launch. + } + + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AccentColor.colorset/Contents.json b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/Contents.json b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..5c2eca5a7 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "mac-icon-16@1x.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "mac-icon-16@2x.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "mac-icon-32@1x.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "mac-icon-32@2x.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "mac-icon-128@1x.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "mac-icon-128@2x.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "mac-icon-256@1x.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "mac-icon-256@2x.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "mac-icon-512@1x.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "mac-icon-512@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png new file mode 100644 index 000000000..0d9f977d0 Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png new file mode 100644 index 000000000..327ad54fe Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png new file mode 100644 index 000000000..4bfa685d5 Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png new file mode 100644 index 000000000..abe86e32f Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png new file mode 100644 index 000000000..327ad54fe Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png new file mode 100644 index 000000000..47938f83d Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png new file mode 100644 index 000000000..abe86e32f Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png new file mode 100644 index 000000000..418d2c4ab Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png new file mode 100644 index 000000000..47938f83d Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png new file mode 100644 index 000000000..2e09553db Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/Contents.json b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/LargeIcon.imageset/Contents.json b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/LargeIcon.imageset/Contents.json new file mode 100644 index 000000000..a19a54922 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Assets.xcassets/LargeIcon.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Base.lproj/Main.storyboard b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Base.lproj/Main.storyboard new file mode 100644 index 000000000..fb8a1899c --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Base.lproj/Main.storyboard @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Info.plist b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Info.plist new file mode 100644 index 000000000..55d956d4f --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Info.plist @@ -0,0 +1,8 @@ + + + + + SFSafariWebExtensionConverterVersion + 26.1.1 + + diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Base.lproj/Main.html b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Base.lproj/Main.html new file mode 100644 index 000000000..39f24bfb7 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Base.lproj/Main.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + KeePassXC-Browser Icon +

You can turn on KeePassXC-Browser’s extension in Safari Extensions preferences.

+

KeePassXC-Browser’s extension is currently on. You can turn it off in Safari Extensions preferences.

+

KeePassXC-Browser’s extension is currently off. You can turn it on in Safari Extensions preferences.

+ + + diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Icon.png b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Icon.png new file mode 100644 index 000000000..69b0fe24e Binary files /dev/null and b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Icon.png differ diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Script.js b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Script.js new file mode 100644 index 000000000..47b8c9a4e --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Script.js @@ -0,0 +1,22 @@ +function show(enabled, useSettingsInsteadOfPreferences) { + if (useSettingsInsteadOfPreferences) { + document.getElementsByClassName('state-on')[0].innerText = "KeePassXC-Browser’s extension is currently on. You can turn it off in the Extensions section of Safari Settings."; + document.getElementsByClassName('state-off')[0].innerText = "KeePassXC-Browser’s extension is currently off. You can turn it on in the Extensions section of Safari Settings."; + document.getElementsByClassName('state-unknown')[0].innerText = "You can turn on KeePassXC-Browser’s extension in the Extensions section of Safari Settings."; + document.getElementsByClassName('open-preferences')[0].innerText = "Quit and Open Safari Settings…"; + } + + if (typeof enabled === "boolean") { + document.body.classList.toggle(`state-on`, enabled); + document.body.classList.toggle(`state-off`, !enabled); + } else { + document.body.classList.remove(`state-on`); + document.body.classList.remove(`state-off`); + } +} + +function openPreferences() { + webkit.messageHandlers.controller.postMessage("open-preferences"); +} + +document.querySelector("button.open-preferences").addEventListener("click", openPreferences); diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Style.css b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Style.css new file mode 100644 index 000000000..cbde9e697 --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/Resources/Style.css @@ -0,0 +1,45 @@ +* { + -webkit-user-select: none; + -webkit-user-drag: none; + cursor: default; +} + +:root { + color-scheme: light dark; + + --spacing: 20px; +} + +html { + height: 100%; +} + +body { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + + gap: var(--spacing); + margin: 0 calc(var(--spacing) * 2); + height: 100%; + + font: -apple-system-short-body; + text-align: center; +} + +body:not(.state-on, .state-off) :is(.state-on, .state-off) { + display: none; +} + +body.state-on :is(.state-off, .state-unknown) { + display: none; +} + +body.state-off :is(.state-on, .state-unknown) { + display: none; +} + +button { + font-size: 1em; +} diff --git a/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/ViewController.swift b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/ViewController.swift new file mode 100644 index 000000000..b8553909a --- /dev/null +++ b/keepassxc-browser-safari/KeePassXC-Browser/KeePassXC-Browser/ViewController.swift @@ -0,0 +1,57 @@ +// +// ViewController.swift +// KeePassXC-Browser +// +// Created by varjolintu on 12.12.2025. +// + +import Cocoa +import SafariServices +import WebKit + +let extensionBundleIdentifier = "org.keepassxc.KeePassXC-Browser.Extension" + +class ViewController: NSViewController, WKNavigationDelegate, WKScriptMessageHandler { + + @IBOutlet var webView: WKWebView! + + override func viewDidLoad() { + super.viewDidLoad() + + self.webView.navigationDelegate = self + + self.webView.configuration.userContentController.add(self, name: "controller") + + self.webView.loadFileURL(Bundle.main.url(forResource: "Main", withExtension: "html")!, allowingReadAccessTo: Bundle.main.resourceURL!) + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + 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 #available(macOS 13, *) { + webView.evaluateJavaScript("show(\(state.isEnabled), true)") + } else { + webView.evaluateJavaScript("show(\(state.isEnabled), false)") + } + } + } + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if (message.body as! String != "open-preferences") { + return; + } + + SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in + DispatchQueue.main.async { + NSApplication.shared.terminate(nil) + } + } + } + +} diff --git a/keepassxc-browser/_locales/en/messages.json b/keepassxc-browser/_locales/en/messages.json index 41a9d5209..59d6c474b 100644 --- a/keepassxc-browser/_locales/en/messages.json +++ b/keepassxc-browser/_locales/en/messages.json @@ -870,6 +870,22 @@ "message": "Allow filling HTTP Basic Auth credentials", "description": "Allow filling HTTP Basic Auth credentials checkbox text." }, + "optionsConnectionMethod": { + "message": "Connection method", + "description": "Connection method selection text." + }, + "optionsConnectionMethodHelpText": { + "message": "If native messaging is blocked in your browser, you can switch to a direct WebSocket sonnection. The feature must be enabled from KeePassXC side to work. Browser restart is required.", + "description": "Connection method help text." + }, + "optionsConnectionMethodNativeMessaging": { + "message": "Native messaging", + "description": "Native messaging option for Connection method." + }, + "optionsConnectionMethodWebSocket": { + "message": "WebSocket", + "description": "WebSocket option for Connection method." + }, "optionsDebugLogging": { "message": "Debug logging", "description": "Debug logging checkbox text." diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index 0b6095d5a..91d0e599f 100755 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -83,7 +83,7 @@ browserAction.generateIconName = async function(iconType) { style = page.settings.colorTheme; } } - const filetype = page.isFirefox ? 'svg' : 'png'; + const filetype = (page.isFirefox || page.isSafari) ? 'svg' : 'png'; return `/icons/toolbar/${style}/${name}.${filetype}`; }; diff --git a/keepassxc-browser/background/client.js b/keepassxc-browser/background/client.js index c98b01dec..71e210460 100644 --- a/keepassxc-browser/background/client.js +++ b/keepassxc-browser/background/client.js @@ -5,6 +5,7 @@ keepassClient.keySize = 24; keepassClient.messageTimeout = 500; // Milliseconds keepassClient.nativeHostName = 'org.keepassxc.keepassxc_browser'; keepassClient.nativePort = null; +keepassClient.webSocket = null; const kpErrors = { UNKNOWN_ERROR: 0, @@ -157,7 +158,10 @@ class Message { //-------------------------------------------------------------------------- keepassClient.sendNativeMessage = async function(request, enableTimeout = false, timeoutValue) { - if (!keepassClient.nativePort) { + if (page?.settings?.connectionMethod === ConnectionMethod.WEBSOCKET && !keepassClient.webSocket) { + logError('No WebSocket defined.'); + return; + } else if (page?.settings?.connectionMethod === ConnectionMethod.NATIVE_MESSAGING && !keepassClient.nativePort) { logError('No native messaging port defined.'); return; } @@ -167,7 +171,11 @@ keepassClient.sendNativeMessage = async function(request, enableTimeout = false, messageBuffer.addMessage(message); }); - keepassClient.nativePort.postMessage(request); + if (page.isSafari || page?.settings?.connectionMethod === ConnectionMethod.WEBSOCKET) { + keepassClient.webSocket.send(JSON.stringify(request)); + } else { + keepassClient.nativePort.postMessage(request); + } const response = await message.promise; @@ -400,7 +408,7 @@ function onDisconnected() { page.clearAllLogins(); keepass.updatePopup('cross'); keepass.updateDatabaseHashToContent(); - logError(`Failed to connect: ${(browser.runtime.lastError === null ? 'Unknown error' : browser.runtime.lastError.message)}`); + logError(`Failed to connect: ${(browser.runtime.lastError === null ? 'Unknown error' : browser.runtime.lastError?.message)}`); } keepassClient.onNativeMessage = function(response) { @@ -413,3 +421,42 @@ keepassClient.onNativeMessage = function(response) { // Generic response handling keepassClient.handleNativeMessage(response); }; + +//-------------------------------------------------------------------------- +// WebSocket related +//-------------------------------------------------------------------------- + +keepassClient.connectToWebSocket = async function() { + return new Promise((resolve, reject) => { + if (keepassClient.webSocket) { + keepassClient.webSocket.close(); + } + + console.log(`${EXTENSION_NAME}: Connecting to WebSocket`); + + try { + keepassClient.webSocket = new WebSocket('ws://localhost:7580'); + keepassClient.webSocket.addEventListener('close', (event) => { + logError('Close WebSocket:', event); + onDisconnected(); + reject(); + }); + keepassClient.webSocket.addEventListener('error', (event) => { + logError('WebSocket error:', event); + onDisconnected(); + reject(); + }); + keepassClient.webSocket.addEventListener('message', (event) => { + keepassClient.onNativeMessage(JSON.parse(event?.data)); + }); + keepassClient.webSocket.addEventListener('open', (event) => { + console.log(`${EXTENSION_NAME}: WebSocket connected`); + keepass.isConnected = true; + resolve(); + }); + } catch (e) { + keepassClient.webSocket = null; + onDisconnected(); + } + }); +}; diff --git a/keepassxc-browser/background/httpauth.js b/keepassxc-browser/background/httpauth.js index 64cc278f6..a3dbfde3c 100755 --- a/keepassxc-browser/background/httpauth.js +++ b/keepassxc-browser/background/httpauth.js @@ -6,6 +6,10 @@ httpAuth.requests = []; httpAuth.pendingCallbacks = []; httpAuth.init = function() { + if (page.isSafari) { + return; + } + let handleReq = httpAuth.handleRequestPromise; let reqType = 'blocking'; diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index c1d136706..2e8a50277 100755 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -805,7 +805,12 @@ keepass.disableAutomaticReconnect = function() { }; keepass.reconnect = async function(tab = null, connectionTimeout = 1500) { - keepassClient.connectToNative(); + if (page?.settings?.connectionMethod === ConnectionMethod.WEBSOCKET) { + await keepassClient.connectToWebSocket(); + } else { + keepassClient.connectToNative(); + } + keepass.generateNewKeyPair(); const keyChangeResult = await keepass.changePublicKeys(tab, !!connectionTimeout, connectionTimeout).catch(() => false); diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index 1476a8b04..83f50475b 100755 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -1,5 +1,10 @@ 'use strict'; +const ConnectionMethod = { + NATIVE_MESSAGING: 'nativemessaging', + WEBSOCKET: 'websocket', +}; + const defaultSettings = { afterFillSorting: SORT_BY_MATCHING_CREDENTIALS_SETTING, afterFillSortingTotp: SORT_BY_RELEVANT_ENTRY, @@ -15,6 +20,7 @@ const defaultSettings = { checkUpdateKeePassXC: CHECK_UPDATE_NEVER, clearCredentialsTimeout: 10, colorTheme: 'system', + connectionMethod: isSafari() ? ConnectionMethod.WEBSOCKET : ConnectionMethod.NATIVE_MESSAGING, credentialSorting: SORT_BY_GROUP_AND_TITLE, debugLogging: false, defaultGroup: '', @@ -50,6 +56,7 @@ page.clearCredentialsTimeout = null; page.currentRequest = {}; page.currentTabId = -1; page.isFirefox = false; +page.isSafari = false; page.manualFill = ManualFill.NONE; page.menuContexts = [ 'editable' ]; page.passwordFilled = false; @@ -68,6 +75,7 @@ page.initBrowser = async function() { navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1 || typeof browser.runtime.getBrowserInfo === 'function'; + page.isSafari = isSafari(); }; page.initSettings = async function() { @@ -75,25 +83,27 @@ page.initSettings = async function() { const item = await browser.storage.local.get({ 'settings': {} }); // Load managed settings if found - if (page.isFirefox && typeof(browser.storage.managed) === 'object') { - try { - const managedSettings = await browser.storage.managed.get('settings'); - if (managedSettings?.settings) { - debugLogMessage('Managed settings found.'); - item.settings = managedSettings.settings; + if (!page.isSafari) { + if (page.isFirefox && typeof(browser.storage.managed) === 'object') { + try { + const managedSettings = await browser.storage.managed.get('settings'); + if (managedSettings?.settings) { + debugLogMessage('Managed settings found.'); + item.settings = managedSettings.settings; + } + } catch (err) { + debugLogMessage('page.initSettings: ' + err); } - } catch (err) { - debugLogMessage('page.initSettings: ' + err); + } else if (typeof chrome.storage.managed === 'object') { + chrome.storage.managed.get('settings').then((managedSettings) => { + if (managedSettings?.settings) { + debugLogMessage('Managed settings found.'); + item.settings = managedSettings.settings; + } + }).catch((err) => { + debugLogMessage('page.initSettings: ' + err); + }); } - } else if (typeof chrome.storage.managed === 'object') { - chrome.storage.managed.get('settings').then((managedSettings) => { - if (managedSettings?.settings) { - debugLogMessage('Managed settings found.'); - item.settings = managedSettings.settings; - } - }).catch((err) => { - debugLogMessage('page.initSettings: ' + err); - }); } page.settings = item.settings; diff --git a/keepassxc-browser/common/global.js b/keepassxc-browser/common/global.js index 10f58f60f..7310550b6 100755 --- a/keepassxc-browser/common/global.js +++ b/keepassxc-browser/common/global.js @@ -36,6 +36,12 @@ const isEdge = function() { return navigator.userAgent.indexOf('Edg') !== -1; }; +const isSafari = function() { + return navigator.userAgent.indexOf('Safari') !== -1 + && navigator.userAgent.indexOf('Chrome') === -1 + && navigator.userAgent.indexOf('Chromium') === -1;; +}; + const showNotification = function(message) { browser.notifications.create({ 'type': 'basic', diff --git a/keepassxc-browser/content/banner.js b/keepassxc-browser/content/banner.js index 7e968b869..8db141d9d 100644 --- a/keepassxc-browser/content/banner.js +++ b/keepassxc-browser/content/banner.js @@ -62,7 +62,9 @@ kpxcBanner.create = async function(credentials = {}) { const bannerInfo = kpxcUI.createElement('div', 'banner-info'); const bannerButtons = kpxcUI.createElement('div', 'banner-buttons'); - const className = kpxc.isFirefox ? 'kpxc-banner-icon-moz' : 'kpxc-banner-icon'; + const className = isSafari() + ? 'kpxc-banner-icon-safari' + : kpxc.isFirefox ? 'kpxc-banner-icon-moz' : 'kpxc-banner-icon'; const icon = kpxcUI.createElement('span', className, { 'alt': 'logo' }); const infoText = kpxcUI.createElement('span', 'banner-info-text', {}, tr('rememberInfoText')); diff --git a/keepassxc-browser/content/custom-fields-banner.js b/keepassxc-browser/content/custom-fields-banner.js index 2b83d6a75..70816db55 100644 --- a/keepassxc-browser/content/custom-fields-banner.js +++ b/keepassxc-browser/content/custom-fields-banner.js @@ -93,7 +93,9 @@ kpxcCustomLoginFieldsBanner.create = async function() { const bannerInfo = kpxcUI.createElement('div', 'banner-info'); const bannerButtons = kpxcUI.createElement('div', 'banner-buttons'); - const iconClassName = kpxc.isFirefox ? 'kpxc-banner-icon-moz' : 'kpxc-banner-icon'; + const iconClassName = isSafari() + ? 'kpxc-banner-icon-safari' + : kpxc.isFirefox ? 'kpxc-banner-icon-moz' : 'kpxc-banner-icon'; const icon = kpxcUI.createElement('span', iconClassName); const infoText = kpxcUI.createElement('span', 'banner-info-text', {}, tr('defineChooseCustomLoginFieldText')); const separator = kpxcUI.createElement('div', 'kpxc-separator'); diff --git a/keepassxc-browser/content/pwgen.js b/keepassxc-browser/content/pwgen.js index 522f073e5..cde438726 100644 --- a/keepassxc-browser/content/pwgen.js +++ b/keepassxc-browser/content/pwgen.js @@ -49,7 +49,7 @@ PasswordIcon.prototype.initField = function(field) { }; PasswordIcon.prototype.createIcon = function(field) { - const className = kpxc.isFirefox ? 'key-moz' : 'key'; + const className = isSafari() ? 'key-safari' : kpxc.isFirefox ? 'key-moz' : 'key'; const size = this.calculateIconSize(field); const icon = kpxcUI.createElement('div', 'kpxc kpxc-pwgen-icon ' + className, diff --git a/keepassxc-browser/content/totp-field.js b/keepassxc-browser/content/totp-field.js index f471d2ceb..e75e9f740 100644 --- a/keepassxc-browser/content/totp-field.js +++ b/keepassxc-browser/content/totp-field.js @@ -139,7 +139,7 @@ TOTPFieldIcon.prototype.initField = async function(field, segmented) { }; TOTPFieldIcon.prototype.createIcon = function(field, segmented = false) { - const className = kpxc.isFirefox ? 'moz' : 'default'; + const className = isSafari() ? 'safari' : kpxc.isFirefox ? 'moz' : 'default'; const size = this.calculateIconSize(field); const icon = kpxcUI.createElement('div', 'kpxc kpxc-totp-icon ' + className, diff --git a/keepassxc-browser/content/ui.js b/keepassxc-browser/content/ui.js index be2d43c35..f253cf4a7 100644 --- a/keepassxc-browser/content/ui.js +++ b/keepassxc-browser/content/ui.js @@ -369,7 +369,9 @@ kpxcUI.createNotification = async function(type, message) { const notification = kpxcUI.createElement('div', 'kpxc-notification kpxc-notification-' + type, {}); type = type.charAt(0).toUpperCase() + type.slice(1) + '!'; - const className = kpxc.isFirefox ? 'kpxc-banner-icon-moz' : 'kpxc-banner-icon'; + const className = isSafari() + ? 'kpxc-banner-icon-safari' + : kpxc.isFirefox ? 'kpxc-banner-icon-moz' : 'kpxc-banner-icon'; const icon = kpxcUI.createElement('span', className, { 'alt': 'logo' }); const label = kpxcUI.createElement('span', 'kpxc-label', {}, type); const msg = kpxcUI.createElement('span', '', {}, message); diff --git a/keepassxc-browser/content/username-field.js b/keepassxc-browser/content/username-field.js index 3316bf66b..36be854a7 100644 --- a/keepassxc-browser/content/username-field.js +++ b/keepassxc-browser/content/username-field.js @@ -44,7 +44,8 @@ class UsernameFieldIcon extends Icon { this.observer.disconnect(); } - this.icon.classList.remove('lock', 'lock-moz', 'unlock', 'unlock-moz', 'disconnected', 'disconnected-moz'); + this.icon.classList.remove('lock', 'lock-moz', 'lock-safari', 'unlock', 'unlock-moz', 'unlock-safari', + 'disconnected', 'disconnected-moz', 'disconnected-safari'); this.icon.classList.add(getIconClassName(state)); this.icon.title = getIconText(state); @@ -147,12 +148,12 @@ const iconClicked = async function(field, icon) { const getIconClassName = function(state = DatabaseState.UNLOCKED) { if (state === DatabaseState.LOCKED) { - return kpxc.isFirefox ? 'lock-moz' : 'lock'; + return isSafari() ? 'lock-safari' : kpxc.isFirefox ? 'lock-moz' : 'lock'; } else if (state === DatabaseState.DISCONNECTED) { - return kpxc.isFirefox ? 'disconnected-moz' : 'disconnected'; + return isSafari() ? 'disconnected-safari' : kpxc.isFirefox ? 'disconnected-moz' : 'disconnected'; } - return kpxc.isFirefox ? 'unlock-moz' : 'unlock'; + return isSafari() ? 'unlock-safari' : kpxc.isFirefox ? 'unlock-moz' : 'unlock'; }; const getIconText = function(state) { diff --git a/keepassxc-browser/css/banner.css b/keepassxc-browser/css/banner.css index 31ee59086..b77ec088a 100644 --- a/keepassxc-browser/css/banner.css +++ b/keepassxc-browser/css/banner.css @@ -81,6 +81,14 @@ div.kpxc-banner .kpxc-banner-icon-moz { background-size: contain; } +div.kpxc-banner .kpxc-banner-icon-safari { + width: 24px; + height: 24px; + overflow: hidden; + background: url('safari-web-extension://__MSG_@@extension_id__/icons/keepassxc.svg') right no-repeat; + background-size: contain; +} + div.kpxc-banner .kpxc-help-icon { width: 24px; height: 24px; @@ -97,6 +105,14 @@ div.kpxc-banner .kpxc-help-icon-moz { background-size: contain; } +div.kpxc-banner .kpxc-help-icon-safari { + width: 24px; + height: 24px; + overflow: hidden; + background: url('safari-web-extension://__MSG_@@extension_id__/icons/help.svg') right no-repeat; + background-size: contain; +} + .kpxc-separator { border-left: 1px solid #ccc; height: 100% !important; diff --git a/keepassxc-browser/css/notification.css b/keepassxc-browser/css/notification.css index 1bb815f33..7cebdeaf0 100644 --- a/keepassxc-browser/css/notification.css +++ b/keepassxc-browser/css/notification.css @@ -43,6 +43,16 @@ background-size: contain; } +.kpxc-notification .kpxc-banner-icon-safari { + width: 24px; + height: 24px; + padding: 10px; + margin-right: 4px; + overflow: hidden; + background: url('safari-web-extension://__MSG_@@extension_id__/icons/keepassxc.svg') right no-repeat; + background-size: contain; +} + .kpxc-notification .kpxc-label { font-weight: bold; } diff --git a/keepassxc-browser/css/pwgen.css b/keepassxc-browser/css/pwgen.css index 4368d25fb..065b48246 100644 --- a/keepassxc-browser/css/pwgen.css +++ b/keepassxc-browser/css/pwgen.css @@ -14,3 +14,8 @@ background: url('moz-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat; background-size: contain; } + +.kpxc-pwgen-icon.key-safari { + background: url('safari-web-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat; + background-size: contain; +} diff --git a/keepassxc-browser/css/totp.css b/keepassxc-browser/css/totp.css index a34ed7cf3..955ff5c4a 100644 --- a/keepassxc-browser/css/totp.css +++ b/keepassxc-browser/css/totp.css @@ -13,4 +13,9 @@ .kpxc-totp-icon.moz { background: url('moz-extension://__MSG_@@extension_id__/icons/otp.svg') right no-repeat; background-size: contain; -} \ No newline at end of file +} + +.kpxc-totp-icon.safari { + background: url('safari-web-extension://__MSG_@@extension_id__/icons/otp.svg') right no-repeat; + background-size: contain; +} diff --git a/keepassxc-browser/css/username.css b/keepassxc-browser/css/username.css index 42d438bd7..7b9686b52 100644 --- a/keepassxc-browser/css/username.css +++ b/keepassxc-browser/css/username.css @@ -15,6 +15,11 @@ background-size: contain; } +.kpxc-username-icon.disconnected-safari { + background: url('safari-web-extension://__MSG_@@extension_id__/icons/disconnected.svg') right no-repeat; + background-size: contain; +} + .kpxc-username-icon.lock { background: url('chrome-extension://__MSG_@@extension_id__/icons/locked.svg') right no-repeat; background-size: contain; @@ -25,6 +30,11 @@ background-size: contain; } +.kpxc-username-icon.lock-safari { + background: url('safari-web-extension://__MSG_@@extension_id__/icons/locked.svg') right no-repeat; + background-size: contain; +} + .kpxc-username-icon.unlock { background: url('chrome-extension://__MSG_@@extension_id__/icons/keepassxc.svg') right no-repeat; background-size: contain; @@ -34,3 +44,8 @@ background: url('moz-extension://__MSG_@@extension_id__/icons/keepassxc.svg') right no-repeat; background-size: contain; } + +.kpxc-username-icon.unlock-safari { + background: url('safari-web-extension://__MSG_@@extension_id__/icons/keepassxc.svg') right no-repeat; + background-size: contain; +} diff --git a/keepassxc-browser/options/options.css b/keepassxc-browser/options/options.css index e7827d38b..8f91eae05 100644 --- a/keepassxc-browser/options/options.css +++ b/keepassxc-browser/options/options.css @@ -63,6 +63,10 @@ input:disabled { opacity: .3!important; } +select:disabled { + opacity: .3!important; +} + footer { display: none; bottom: 1rem; diff --git a/keepassxc-browser/options/options.html b/keepassxc-browser/options/options.html index a9e6997cc..159cbde4d 100644 --- a/keepassxc-browser/options/options.html +++ b/keepassxc-browser/options/options.html @@ -154,7 +154,7 @@

-
+
@@ -278,7 +278,7 @@

-
+
@@ -531,6 +531,18 @@

+ +
+ + +
+
+ +
+
diff --git a/keepassxc-browser/options/options.js b/keepassxc-browser/options/options.js index 3b9aa2803..0b6d91277 100644 --- a/keepassxc-browser/options/options.js +++ b/keepassxc-browser/options/options.js @@ -226,6 +226,13 @@ options.initGeneralSettings = async function() { }); }); + // Connection method + $('#tab-general-settings select#connectionMethod').value = options.settings['connectionMethod']; + $('#tab-general-settings select#connectionMethod').addEventListener('change', async function(e) { + options.settings['connectionMethod'] = e.currentTarget.value; + await options.saveSettings(); + }); + // Default group $('#defaultGroupButton').addEventListener('click', async function() { const value = $('#defaultGroup').value; @@ -873,12 +880,21 @@ options.createWarning = function(elem, text) { }, 5000); }; +options.hideUnsupportedFeatures = function() { + if (isSafari()) { + $('#tab-general-settings select#connectionMethod').disabled = true; + $('#tab-general-settings div#keyboardShortcuts').hide(); + $('#tab-general-settings div#autoFillHttpAuth').hide(); + } +}; + const getBrowserId = function(userAgent) { const browserQueries = [ { findStr: 'Firefox', name: 'Mozilla Firefox' }, { findStr: 'Edg', name: 'Microsoft Edge' }, { findStr: 'OPR', name: 'Opera' }, - { findStr: 'Chrome', name: 'Chrome/Chromium' } + { findStr: 'Chrome', name: 'Chrome/Chromium' }, + { findStr: 'Version', name: 'Safari' } ]; const getVersion = (agent, findStr) => { @@ -991,6 +1007,7 @@ window.addEventListener('scroll', function() { options.initCustomLoginFields(); options.initSitePreferences(); options.initAbout(); + options.hideUnsupportedFeatures(); } catch (err) { console.log('Error loading options page: ' + err); } diff --git a/keepassxc-browser/popups/popup.css b/keepassxc-browser/popups/popup.css index 3f0929fea..8e38231a7 100644 --- a/keepassxc-browser/popups/popup.css +++ b/keepassxc-browser/popups/popup.css @@ -153,6 +153,15 @@ code { width: 2.5rem; } +#choose-custom-login-fields-button-safari { + background-image: url('safari-web-extension://__MSG_@@extension_id__/icons/custom_login_fields.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: 70%; + height: 31px; + width: 2.5rem; +} + #lock-database-button { display: none; width: 2.5rem; diff --git a/keepassxc-browser/popups/popup_functions.js b/keepassxc-browser/popups/popup_functions.js index 30acbb39d..458853746 100644 --- a/keepassxc-browser/popups/popup_functions.js +++ b/keepassxc-browser/popups/popup_functions.js @@ -19,6 +19,8 @@ async function initSettings() { const isFirefox = await browser.runtime.sendMessage({ action: 'is_firefox' }); if (isFirefox) { customLoginFieldsButton.id = 'choose-custom-login-fields-button-moz'; + } else if (isSafari()) { + customLoginFieldsButton.id = 'choose-custom-login-fields-button-safari'; } customLoginFieldsButton.addEventListener('click', async () => {