diff --git a/Info.plist b/Info.plist
index af1e52e..b9e4465 100644
--- a/Info.plist
+++ b/Info.plist
@@ -2,9 +2,7 @@
- LSUIElement
-
- NSFaceIDUsageDescription
- nbox uses Touch ID to protect your secrets.
+ LSApplicationCategoryType
+ public.app-category.utilities
diff --git a/NBox.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/NBox.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 919434a..0000000
--- a/NBox.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/NBox.xcodeproj/xcuserdata/jaspermiddendorp.xcuserdatad/xcschemes/xcschememanagement.plist b/NBox.xcodeproj/xcuserdata/jaspermiddendorp.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index 092d39c..0000000
--- a/NBox.xcodeproj/xcuserdata/jaspermiddendorp.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- SchemeUserState
-
- NBox.xcscheme_^#shared#^_
-
- orderHint
- 0
-
-
-
-
diff --git a/NBox/AppState.swift b/NBox/AppState.swift
index 6450646..ac37d7d 100644
--- a/NBox/AppState.swift
+++ b/NBox/AppState.swift
@@ -69,7 +69,7 @@ class AppState {
}
func revealSecret(account: String) -> Result {
- KeychainManager().get(account: account)
+ KeychainManager().get(account: account, reason: "Reveal value for \"\(account)\"")
}
private var pendingDeletes: [String: DispatchWorkItem] = [:]
@@ -77,7 +77,7 @@ class AppState {
/// Encrypts secret to a temp file, copies a `source <(openssl ...)` command to clipboard.
/// File auto-deletes after 60s. Clipboard auto-clears after 30s.
func shareSecret(account: String) -> Result {
- switch KeychainManager().get(account: account) {
+ switch KeychainManager().get(account: account, reason: "Share \"\(account)\" (encrypted to temp file)") {
case .success(let value):
// Derive env var name from the last path component
let envVar = account.split(separator: "/").last.map(String.init) ?? account
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/Contents.json b/NBox/Assets.xcassets/AppIcon.appiconset/Contents.json
index 3f00db4..64dc11e 100644
--- a/NBox/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/NBox/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,51 +1,61 @@
{
"images" : [
{
+ "filename" : "icon_16x16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
+ "filename" : "icon_16x16@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
+ "filename" : "icon_32x32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
+ "filename" : "icon_32x32@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
+ "filename" : "icon_128x128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
+ "filename" : "icon_128x128@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
+ "filename" : "icon_256x256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
+ "filename" : "icon_256x256@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
+ "filename" : "icon_512x512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
+ "filename" : "icon_512x512@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
new file mode 100644
index 0000000..94a1d8c
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_128x128.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
new file mode 100644
index 0000000..0630bb9
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
new file mode 100644
index 0000000..c89af1f
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_16x16.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
new file mode 100644
index 0000000..81b9090
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
new file mode 100644
index 0000000..0630bb9
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_256x256.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
new file mode 100644
index 0000000..3b55a80
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
new file mode 100644
index 0000000..81b9090
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_32x32.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
new file mode 100644
index 0000000..1074000
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
new file mode 100644
index 0000000..3b55a80
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_512x512.png differ
diff --git a/NBox/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/NBox/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
new file mode 100644
index 0000000..c8affbe
Binary files /dev/null and b/NBox/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ
diff --git a/NBox/ContentView.swift b/NBox/ContentView.swift
deleted file mode 100644
index 837d544..0000000
--- a/NBox/ContentView.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// ContentView.swift
-// NBox
-//
-// Created by Jasper Middendorp on 06/03/2026.
-//
-
-import SwiftUI
-
-struct ContentView: View {
- var body: some View {
- VStack {
- Image(systemName: "globe")
- .imageScale(.large)
- .foregroundStyle(.tint)
- Text("Hello, world!")
- }
- .padding()
- }
-}
-
-#Preview {
- ContentView()
-}
diff --git a/NBox/HotkeyManager.swift b/NBox/HotkeyManager.swift
new file mode 100644
index 0000000..238331b
--- /dev/null
+++ b/NBox/HotkeyManager.swift
@@ -0,0 +1,55 @@
+import Carbon
+import AppKit
+
+/// Registers a global hotkey (Cmd+Shift+K) using the Carbon API.
+/// Works in sandboxed apps without Accessibility permissions.
+final class HotkeyManager {
+ private var hotkeyRef: EventHotKeyRef?
+ private var eventHandler: EventHandlerRef?
+ var onTrigger: (() -> Void)?
+
+ func register() {
+ let hotkeyID = EventHotKeyID(signature: OSType(0x4E424F58), // "NBOX"
+ id: 1)
+
+ // Cmd+Shift+K — kVK_ANSI_K = 0x28
+ let modifiers: UInt32 = UInt32(cmdKey | shiftKey)
+ let status = RegisterEventHotKey(UInt32(kVK_ANSI_K), modifiers, hotkeyID,
+ GetApplicationEventTarget(), 0, &hotkeyRef)
+ guard status == noErr else {
+ print("nbox: failed to register hotkey: \(status)")
+ return
+ }
+
+ // Install Carbon event handler for hotkey events
+ var eventType = EventTypeSpec(eventClass: OSType(kEventClassKeyboard),
+ eventKind: UInt32(kEventHotKeyPressed))
+
+ let handlerBlock: EventHandlerUPP = { _, event, userData -> OSStatus in
+ guard let userData else { return OSStatus(eventNotHandledErr) }
+ let manager = Unmanaged.fromOpaque(userData).takeUnretainedValue()
+ DispatchQueue.main.async {
+ manager.onTrigger?()
+ }
+ return noErr
+ }
+
+ let selfPtr = Unmanaged.passUnretained(self).toOpaque()
+ InstallEventHandler(GetApplicationEventTarget(), handlerBlock, 1, &eventType, selfPtr, &eventHandler)
+ }
+
+ func unregister() {
+ if let hotkeyRef {
+ UnregisterEventHotKey(hotkeyRef)
+ self.hotkeyRef = nil
+ }
+ if let eventHandler {
+ RemoveEventHandler(eventHandler)
+ self.eventHandler = nil
+ }
+ }
+
+ deinit {
+ unregister()
+ }
+}
diff --git a/NBox/KeychainManager.swift b/NBox/KeychainManager.swift
index d07d488..d0259e5 100644
--- a/NBox/KeychainManager.swift
+++ b/NBox/KeychainManager.swift
@@ -116,15 +116,15 @@ struct KeychainManager {
return .success(())
}
- func get(account: String) -> Result {
+ func get(account: String, reason: String? = nil) -> Result {
let context = LAContext()
- context.localizedReason = "Read value for \"\(account)\""
- return get(account: account, context: context)
+ let prompt = reason ?? "Read value for \"\(account)\""
+ return get(account: account, context: context, reason: prompt)
}
/// Read a secret using a pre-authenticated LAContext (avoids repeated Touch ID).
- func get(account: String, context: LAContext) -> Result {
- let query: [String: Any] = [
+ func get(account: String, context: LAContext, reason: String? = nil) -> Result {
+ var query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
@@ -132,6 +132,9 @@ struct KeychainManager {
kSecUseAuthenticationContext as String: context,
kSecUseDataProtectionKeychain as String: true,
]
+ if let reason {
+ query[kSecUseOperationPrompt as String] = reason
+ }
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
diff --git a/NBox/NBox.entitlements b/NBox/NBox.entitlements
index 9b70eed..de4bbf4 100644
--- a/NBox/NBox.entitlements
+++ b/NBox/NBox.entitlements
@@ -3,7 +3,11 @@
com.apple.security.app-sandbox
-
+
+ com.apple.security.network.client
+
+ com.apple.security.network.server
+
keychain-access-groups
$(AppIdentifierPrefix)dev.nobox.nbox
diff --git a/NBox/NBoxApp.swift b/NBox/NBoxApp.swift
index 1951856..33f820b 100644
--- a/NBox/NBoxApp.swift
+++ b/NBox/NBoxApp.swift
@@ -16,11 +16,18 @@ struct NBoxApp: App {
class AppDelegate: NSObject, NSApplicationDelegate {
private var socketServer: SocketServer?
+ private let hotkeyManager = HotkeyManager()
+ private lazy var quickAccessPanel = QuickAccessPanel(appState: AppState.shared)
func applicationDidFinishLaunching(_ notification: Notification) {
socketServer = SocketServer(keychain: KeychainManager())
socketServer?.start()
installCLI()
+
+ hotkeyManager.onTrigger = { [weak self] in
+ self?.quickAccessPanel.toggle()
+ }
+ hotkeyManager.register()
}
/// Copy the bundled nbox-cli to ~/.local/bin/nbox on every launch,
@@ -46,6 +53,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func applicationWillTerminate(_ notification: Notification) {
+ hotkeyManager.unregister()
socketServer?.stop()
AppState.shared.cleanupSessionDir()
}
diff --git a/NBox/QuickAccessPanel.swift b/NBox/QuickAccessPanel.swift
new file mode 100644
index 0000000..73eb20e
--- /dev/null
+++ b/NBox/QuickAccessPanel.swift
@@ -0,0 +1,249 @@
+import AppKit
+import SwiftUI
+
+/// A floating panel that appears near the cursor for quick secret access.
+final class QuickAccessPanel {
+ private var panel: NSPanel?
+ private let appState: AppState
+
+ init(appState: AppState) {
+ self.appState = appState
+ }
+
+ var isVisible: Bool { panel?.isVisible ?? false }
+
+ func toggle() {
+ if let panel, panel.isVisible {
+ dismiss()
+ } else {
+ show()
+ }
+ }
+
+ func show() {
+ dismiss()
+
+ let view = QuickAccessView(appState: appState, onDismiss: { [weak self] in
+ self?.dismiss()
+ })
+
+ let hostingView = NSHostingView(rootView: view)
+ hostingView.frame = NSRect(x: 0, y: 0, width: 300, height: 360)
+
+ let panel = NSPanel(
+ contentRect: hostingView.frame,
+ styleMask: [.nonactivatingPanel, .titled, .fullSizeContentView],
+ backing: .buffered,
+ defer: false
+ )
+ panel.isFloatingPanel = true
+ panel.level = .floating
+ panel.titleVisibility = .hidden
+ panel.titlebarAppearsTransparent = true
+ panel.isMovableByWindowBackground = true
+ panel.contentView = hostingView
+ panel.backgroundColor = .clear
+ panel.isOpaque = false
+ panel.hasShadow = true
+ panel.hidesOnDeactivate = false
+
+ // Position near mouse cursor
+ let mouseLocation = NSEvent.mouseLocation
+ let screenFrame = NSScreen.main?.visibleFrame ?? .zero
+ var origin = NSPoint(x: mouseLocation.x - 150, y: mouseLocation.y - 380)
+
+ // Keep on screen
+ origin.x = max(screenFrame.minX, min(origin.x, screenFrame.maxX - 300))
+ origin.y = max(screenFrame.minY, min(origin.y, screenFrame.maxY - 360))
+
+ panel.setFrameOrigin(origin)
+ panel.makeKeyAndOrderFront(nil)
+
+ // Activate the app so the panel can receive keyboard input
+ NSApp.activate(ignoringOtherApps: true)
+
+ self.panel = panel
+ }
+
+ func dismiss() {
+ panel?.orderOut(nil)
+ panel = nil
+ }
+}
+
+struct QuickAccessView: View {
+ let appState: AppState
+ let onDismiss: () -> Void
+ @State private var search = ""
+ @State private var error: String?
+ @State private var copiedAccount: String?
+ @FocusState private var searchFocused: Bool
+
+ private var filtered: [SecretInfo] {
+ if search.isEmpty { return appState.accounts }
+ return appState.accounts.filter { $0.account.localizedCaseInsensitiveContains(search) }
+ }
+
+ var body: some View {
+ VStack(spacing: 0) {
+ // Search bar
+ HStack(spacing: 6) {
+ Image(systemName: "magnifyingglass")
+ .foregroundStyle(.secondary)
+ .font(.system(size: 13))
+ TextField("Search secrets...", text: $search)
+ .textFieldStyle(.plain)
+ .font(.system(size: 14))
+ .focused($searchFocused)
+ Button(action: onDismiss) {
+ Image(systemName: "xmark.circle.fill")
+ .foregroundStyle(.tertiary)
+ }
+ .buttonStyle(.plain)
+ }
+ .padding(10)
+
+ Divider()
+
+ // Results
+ if filtered.isEmpty {
+ Spacer()
+ Text(search.isEmpty ? "No secrets stored" : "No matches")
+ .foregroundStyle(.secondary)
+ .font(.system(size: 13))
+ Spacer()
+ } else {
+ ScrollView {
+ LazyVStack(alignment: .leading, spacing: 0) {
+ ForEach(filtered, id: \.account) { info in
+ QuickAccessRow(
+ info: info,
+ isCopied: copiedAccount == info.account,
+ onCopy: { copySecret(info.account) }
+ )
+ }
+ }
+ .padding(.vertical, 4)
+ }
+ }
+
+ if let error {
+ Divider()
+ Text(error)
+ .font(.caption)
+ .foregroundStyle(.red)
+ .padding(.horizontal, 10)
+ .padding(.vertical, 4)
+ }
+
+ Divider()
+
+ HStack {
+ Text("\u{2318}\u{21E7}K to toggle")
+ .font(.system(size: 10))
+ .foregroundStyle(.tertiary)
+ Spacer()
+ Text("Touch ID to copy")
+ .font(.system(size: 10))
+ .foregroundStyle(.tertiary)
+ }
+ .padding(.horizontal, 10)
+ .padding(.vertical, 5)
+ }
+ .frame(width: 300, height: 360)
+ .background(.ultraThinMaterial)
+ .clipShape(RoundedRectangle(cornerRadius: 12))
+ .onAppear {
+ searchFocused = true
+ appState.refresh()
+ }
+ .onExitCommand {
+ onDismiss()
+ }
+ }
+
+ private func copySecret(_ account: String) {
+ error = nil
+ switch appState.revealSecret(account: account) {
+ case .success(let value):
+ // For structured types, extract the most useful value
+ let meta = appState.metadataFor(account: account)
+ let copyValue: String
+ if meta?.type == "login", let decoded = CredentialValue.decodeLogin(value) {
+ // Copy password (most common need); username is usually not secret
+ copyValue = decoded.password
+ } else if meta?.type == "api_key", let decoded = CredentialValue.decodeAPIKey(value) {
+ copyValue = decoded.primary
+ } else if meta?.type == "recovery_code", let codes = CredentialValue.decodeRecoveryCodes(value) {
+ copyValue = codes.joined(separator: "\n")
+ } else {
+ copyValue = value
+ }
+
+ NSPasteboard.general.clearContents()
+ NSPasteboard.general.setString(copyValue, forType: .string)
+ copiedAccount = account
+
+ // Auto-clear clipboard after 30s
+ let changeCount = NSPasteboard.general.changeCount
+ DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
+ if NSPasteboard.general.changeCount == changeCount {
+ NSPasteboard.general.clearContents()
+ }
+ }
+
+ // Dismiss after brief visual feedback
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+ onDismiss()
+ }
+ case .failure(let err):
+ if case .authCanceled = err {
+ // User canceled Touch ID — just stay open
+ } else {
+ error = err.description
+ }
+ }
+ }
+}
+
+private struct QuickAccessRow: View {
+ let info: SecretInfo
+ let isCopied: Bool
+ let onCopy: () -> Void
+
+ var body: some View {
+ Button(action: onCopy) {
+ HStack {
+ VStack(alignment: .leading, spacing: 2) {
+ Text(info.account)
+ .font(.system(size: 12, design: .monospaced))
+ .lineLimit(1)
+ .truncationMode(.middle)
+ if let peek = info.metadata?.peek {
+ Text("\(peek)...")
+ .font(.system(size: 10, design: .monospaced))
+ .foregroundStyle(.tertiary)
+ }
+ }
+ Spacer()
+ if isCopied {
+ Image(systemName: "checkmark.circle.fill")
+ .foregroundStyle(.green)
+ .font(.system(size: 14))
+ } else {
+ if let type = info.metadata?.type {
+ TypeBadge(type: type)
+ }
+ Image(systemName: "key.fill")
+ .foregroundStyle(.secondary)
+ .font(.system(size: 11))
+ }
+ }
+ .padding(.horizontal, 10)
+ .padding(.vertical, 6)
+ .contentShape(Rectangle())
+ }
+ .buttonStyle(.plain)
+ .background(isCopied ? Color.green.opacity(0.1) : Color.clear)
+ }
+}
diff --git a/NBox/SecretListView.swift b/NBox/SecretListView.swift
index a230e12..193a512 100644
--- a/NBox/SecretListView.swift
+++ b/NBox/SecretListView.swift
@@ -99,6 +99,9 @@ struct SecretListView: View {
.font(.caption)
.buttonStyle(.plain)
.foregroundStyle(copiedInstructions ? .green : Color(red: 0xFE/255, green: 0x79/255, blue: 0x5D/255))
+ Link("No-Box-Dev", destination: URL(string: "https://noboxdev.com")!)
+ .font(.caption)
+ .foregroundStyle(.secondary)
Button("Quit") {
NSApplication.shared.terminate(nil)
}
@@ -539,11 +542,16 @@ struct OnboardingView: View {
Divider()
- HStack {
- Spacer()
- Button("Got it") { onDismiss() }
- .keyboardShortcut(.defaultAction)
- Spacer()
+ VStack(spacing: 4) {
+ HStack {
+ Spacer()
+ Button("Got it") { onDismiss() }
+ .keyboardShortcut(.defaultAction)
+ Spacer()
+ }
+ Link("noboxdev.com", destination: URL(string: "https://noboxdev.com")!)
+ .font(.caption2)
+ .foregroundStyle(.tertiary)
}
.padding(.vertical, 8)
}
diff --git a/NBox/SocketServer.swift b/NBox/SocketServer.swift
index 62227c2..0e8b5aa 100644
--- a/NBox/SocketServer.swift
+++ b/NBox/SocketServer.swift
@@ -287,7 +287,7 @@ class SocketServer {
sendResponse(clientSocket, ok: true, value: cached)
return
}
- switch keychain.get(account: account) {
+ switch keychain.get(account: account, reason: "CLI: read value for \"\(account)\"") {
case .success(let value):
sendResponse(clientSocket, ok: true, value: value)
case .failure(let err):
diff --git a/NBox.xcodeproj/project.pbxproj b/Noxkey.xcodeproj/project.pbxproj
similarity index 89%
rename from NBox.xcodeproj/project.pbxproj
rename to Noxkey.xcodeproj/project.pbxproj
index 9fc8e88..7eae64c 100644
--- a/NBox.xcodeproj/project.pbxproj
+++ b/Noxkey.xcodeproj/project.pbxproj
@@ -7,7 +7,7 @@
objects = {
/* Begin PBXFileReference section */
- 0228B8292F5B61030021FBA2 /* NBox.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NBox.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0228B8292F5B61030021FBA2 /* Noxkey.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Noxkey.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -40,7 +40,7 @@
0228B82A2F5B61030021FBA2 /* Products */ = {
isa = PBXGroup;
children = (
- 0228B8292F5B61030021FBA2 /* NBox.app */,
+ 0228B8292F5B61030021FBA2 /* Noxkey.app */,
);
name = Products;
sourceTree = "";
@@ -48,9 +48,9 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- 0228B8282F5B61030021FBA2 /* NBox */ = {
+ 0228B8282F5B61030021FBA2 /* Noxkey */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 0228B8342F5B61050021FBA2 /* Build configuration list for PBXNativeTarget "NBox" */;
+ buildConfigurationList = 0228B8342F5B61050021FBA2 /* Build configuration list for PBXNativeTarget "Noxkey" */;
buildPhases = (
0228B8252F5B61030021FBA2 /* Sources */,
0228B8262F5B61030021FBA2 /* Frameworks */,
@@ -63,11 +63,11 @@
fileSystemSynchronizedGroups = (
0228B82B2F5B61030021FBA2 /* NBox */,
);
- name = NBox;
+ name = Noxkey;
packageProductDependencies = (
);
productName = NBox;
- productReference = 0228B8292F5B61030021FBA2 /* NBox.app */;
+ productReference = 0228B8292F5B61030021FBA2 /* Noxkey.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
@@ -86,7 +86,7 @@
};
};
};
- buildConfigurationList = 0228B8242F5B61030021FBA2 /* Build configuration list for PBXProject "NBox" */;
+ buildConfigurationList = 0228B8242F5B61030021FBA2 /* Build configuration list for PBXProject "Noxkey" */;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -100,7 +100,7 @@
projectDirPath = "";
projectRoot = "";
targets = (
- 0228B8282F5B61030021FBA2 /* NBox */,
+ 0228B8282F5B61030021FBA2 /* Noxkey */,
);
};
/* End PBXProject section */
@@ -262,13 +262,17 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = Noxkey;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
+ INFOPLIST_KEY_LSUIElement = YES;
+ INFOPLIST_KEY_NSFaceIDUsageDescription = "nbox uses Touch ID to protect your secrets.";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = dev.nobox.nbox;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.noboxdev.Noxkey;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -293,13 +297,17 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = Noxkey;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
+ INFOPLIST_KEY_LSUIElement = YES;
+ INFOPLIST_KEY_NSFaceIDUsageDescription = "nbox uses Touch ID to protect your secrets.";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = dev.nobox.nbox;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.noboxdev.Noxkey;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -310,7 +318,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 0228B8242F5B61030021FBA2 /* Build configuration list for PBXProject "NBox" */ = {
+ 0228B8242F5B61030021FBA2 /* Build configuration list for PBXProject "Noxkey" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0228B8322F5B61050021FBA2 /* Debug */,
@@ -319,7 +327,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 0228B8342F5B61050021FBA2 /* Build configuration list for PBXNativeTarget "NBox" */ = {
+ 0228B8342F5B61050021FBA2 /* Build configuration list for PBXNativeTarget "Noxkey" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0228B8352F5B61050021FBA2 /* Debug */,