Repository: Lakr233/ActionBee
Branch: main
Commit: b9807306513d
Files: 286
Total size: 1.3 MB
Directory structure:
gitextract_cxsqbwhp/
├── .gitignore
├── .gitmodules
├── .root
├── App/
│ └── Action/
│ ├── Action/
│ │ ├── Action.entitlements
│ │ ├── Application/
│ │ │ ├── Action.entitlements
│ │ │ ├── ActionApp.swift
│ │ │ ├── AppDelegate.swift
│ │ │ ├── AppSetup.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AccentColor.colorset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Avatar.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── License.txt
│ │ │ ├── en.lproj/
│ │ │ │ └── Localizable.strings
│ │ │ └── zh-Hans.lproj/
│ │ │ └── Localizable.strings
│ │ ├── Backend/
│ │ │ ├── Action/
│ │ │ │ ├── ActionManager+Artifact.swift
│ │ │ │ ├── ActionManager+Event.swift
│ │ │ │ ├── ActionManager+History.swift
│ │ │ │ ├── ActionManager+Module.swift
│ │ │ │ ├── ActionManager.swift
│ │ │ │ ├── ActionModuleTemplates/
│ │ │ │ │ ├── ActionManager+Template.swift
│ │ │ │ │ ├── Template+Executable.swift
│ │ │ │ │ ├── Template+Node.swift
│ │ │ │ │ ├── Template+Python.swift
│ │ │ │ │ └── Template+Swift.swift
│ │ │ │ └── ActionTemplates/
│ │ │ │ └── .templates
│ │ │ ├── Config/
│ │ │ │ └── Config.swift
│ │ │ ├── Executor/
│ │ │ │ └── Executor.swift
│ │ │ ├── PasteboardManager/
│ │ │ │ ├── PasteboardManager+Event.swift
│ │ │ │ └── PasteboardManager.swift
│ │ │ └── StatusBarManager/
│ │ │ └── StatusBarManager.swift
│ │ ├── Extension/
│ │ │ ├── AES.swift
│ │ │ ├── Data.swift
│ │ │ ├── DispatchQueue.swift
│ │ │ ├── Notification.swift
│ │ │ ├── Result.swift
│ │ │ ├── Throttle.swift
│ │ │ ├── UserDefault.swift
│ │ │ └── View.swift
│ │ └── Interface/
│ │ ├── ActionModule/
│ │ │ ├── ModuleCreateView.swift
│ │ │ ├── ModuleEditView.swift
│ │ │ ├── ModuleElementView.swift
│ │ │ ├── ModuleImportView.swift
│ │ │ └── ModuleManageView.swift
│ │ ├── Effect/
│ │ │ └── RandomCodeTextView.swift
│ │ ├── Generic/
│ │ │ ├── ApplicationView.swift
│ │ │ ├── DiagnosticLogView.swift
│ │ │ ├── HistoryView.swift
│ │ │ ├── LicenseView.swift
│ │ │ ├── MainView.swift
│ │ │ ├── SettingView.swift
│ │ │ ├── SidebarView.swift
│ │ │ └── WelcomeView.swift
│ │ ├── Menubar/
│ │ │ ├── Menubar.swift
│ │ │ └── MenubarView.swift
│ │ └── Toast/
│ │ └── Toast.swift
│ └── Action.xcodeproj/
│ └── project.pbxproj
├── App.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── External/
│ ├── AuxiliaryExecute/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── Package.swift
│ │ ├── README.md
│ │ ├── Sources/
│ │ │ └── AuxiliaryExecute/
│ │ │ ├── AuxiliaryExecute+Async.swift
│ │ │ ├── AuxiliaryExecute+Shell.swift
│ │ │ ├── AuxiliaryExecute+Spawn.swift
│ │ │ └── AuxiliaryExecute.swift
│ │ └── Tests/
│ │ └── AuxiliaryExecuteTests/
│ │ └── AuxiliaryExecuteTests.swift
│ ├── Colorful/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── Package.swift
│ │ ├── README.md
│ │ └── Sources/
│ │ └── Colorful/
│ │ ├── Colorful.swift
│ │ ├── ColorfulView.swift
│ │ └── PointRandomization.swift
│ ├── KeychainAccess/
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── Examples/
│ │ │ └── Example-iOS/
│ │ │ ├── Example-iOS/
│ │ │ │ ├── AccountsViewController.swift
│ │ │ │ ├── AppDelegate.swift
│ │ │ │ ├── Base.lproj/
│ │ │ │ │ ├── LaunchScreen.xib
│ │ │ │ │ └── Main.storyboard
│ │ │ │ ├── Example-iOS.entitlements
│ │ │ │ ├── Images.xcassets/
│ │ │ │ │ └── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Info.plist
│ │ │ │ └── InputViewController.swift
│ │ │ └── Example-iOS.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── Example-iOS.xcscheme
│ │ ├── KeychainAccess.podspec
│ │ ├── KeychainAccess.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ ├── LICENSE
│ │ ├── Lib/
│ │ │ ├── Certificates/
│ │ │ │ ├── KeychainAccess_Tests.provisionprofile.enc
│ │ │ │ ├── apple.cer
│ │ │ │ ├── developer_id_app.p12.enc
│ │ │ │ ├── iOS_Development.mobileprovision.enc
│ │ │ │ ├── ios_developer.p12.enc
│ │ │ │ └── tvOS_Development.mobileprovision.enc
│ │ │ ├── Configurations/
│ │ │ │ ├── Base.xcconfig
│ │ │ │ ├── Debug.xcconfig
│ │ │ │ ├── KeychainAccess.xcconfig
│ │ │ │ ├── Release.xcconfig
│ │ │ │ ├── TestHost.xcconfig
│ │ │ │ └── Tests.xcconfig
│ │ │ ├── Gemfile
│ │ │ ├── KeychainAccess/
│ │ │ │ ├── Info.plist
│ │ │ │ ├── Keychain.swift
│ │ │ │ └── KeychainAccess.h
│ │ │ ├── KeychainAccess.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ ├── KeychainAccess.xcscheme
│ │ │ │ └── TestHost.xcscheme
│ │ │ ├── KeychainAccessTests/
│ │ │ │ ├── EnumTests.swift
│ │ │ │ ├── ErrorTypeTests.swift
│ │ │ │ ├── Info.plist
│ │ │ │ ├── KeychainAccessTests.swift
│ │ │ │ └── SharedCredentialTests.swift
│ │ │ ├── Rakefile
│ │ │ ├── Scripts/
│ │ │ │ ├── add_key.sh
│ │ │ │ └── decode_cert.sh
│ │ │ ├── TestHost/
│ │ │ │ ├── AppDelegate.swift
│ │ │ │ ├── Assets.xcassets/
│ │ │ │ │ └── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Info.plist
│ │ │ │ └── TestHost.entitlements
│ │ │ └── TestHost-MacCatalyst/
│ │ │ ├── KeychainAccessTests-MacCatalyst/
│ │ │ │ ├── EnumTests.swift
│ │ │ │ ├── ErrorTypeTests.swift
│ │ │ │ ├── Info.plist
│ │ │ │ └── KeychainAccessTests.swift
│ │ │ ├── TestHost-MacCatalyst/
│ │ │ │ ├── AppDelegate.swift
│ │ │ │ ├── Assets.xcassets/
│ │ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Base.lproj/
│ │ │ │ │ ├── LaunchScreen.storyboard
│ │ │ │ │ └── Main.storyboard
│ │ │ │ ├── Info.plist
│ │ │ │ ├── SceneDelegate.swift
│ │ │ │ ├── TestHost-MacCatalyst.entitlements
│ │ │ │ └── ViewController.swift
│ │ │ └── TestHost-MacCatalyst.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── TestHost-MacCatalyst.xcscheme
│ │ ├── Package.swift
│ │ ├── Package@swift-5.3.swift
│ │ ├── README.md
│ │ └── Sources/
│ │ └── Keychain.swift
│ └── SymbolPicker/
│ ├── .gitignore
│ ├── LICENSE
│ ├── Package.swift
│ ├── README.md
│ └── Sources/
│ └── SymbolPicker/
│ ├── Resources/
│ │ ├── en.lproj/
│ │ │ └── Localizable.strings
│ │ ├── sfsymbols.txt
│ │ └── zh_CN.lproj/
│ │ └── Localizable.strings
│ └── SymbolPicker.swift
├── LICENSE
├── README.md
└── Resources/
├── ModuleSample/
│ ├── Module Export - Link Cleaner/
│ │ ├── .ActionManifest.plist
│ │ ├── .gitignore
│ │ ├── .supplement/
│ │ │ ├── Binary/
│ │ │ │ └── CommandLineBridge/
│ │ │ │ ├── CommandLineBridge/
│ │ │ │ │ └── main.swift
│ │ │ │ └── CommandLineBridge.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── CommandLineBridge.xcscheme
│ │ │ ├── Communicator/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Communicator/
│ │ │ │ ├── Communicator.h
│ │ │ │ ├── Communicator.m
│ │ │ │ └── include/
│ │ │ │ └── Communicator.h
│ │ │ ├── Definition/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Definition/
│ │ │ │ └── Definition.swift
│ │ │ ├── compile.sh
│ │ │ └── launch.sh
│ │ ├── App.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── Source/
│ │ ├── .gitignore
│ │ ├── Package.swift
│ │ └── Sources/
│ │ └── Source/
│ │ ├── CleanerRule/
│ │ │ ├── CleanerRule.swift
│ │ │ ├── Rule+BiliBili.swift
│ │ │ └── Rule+Twitter.swift
│ │ └── Source.swift
│ ├── Module Export - Multiline Init Formatter/
│ │ ├── .ActionManifest.plist
│ │ ├── .gitignore
│ │ ├── .supplement/
│ │ │ ├── Binary/
│ │ │ │ └── CommandLineBridge/
│ │ │ │ ├── CommandLineBridge/
│ │ │ │ │ └── main.swift
│ │ │ │ └── CommandLineBridge.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── CommandLineBridge.xcscheme
│ │ │ ├── Communicator/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Communicator/
│ │ │ │ ├── Communicator.h
│ │ │ │ ├── Communicator.m
│ │ │ │ └── include/
│ │ │ │ └── Communicator.h
│ │ │ ├── Definition/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Definition/
│ │ │ │ └── Definition.swift
│ │ │ ├── compile.sh
│ │ │ └── launch.sh
│ │ ├── App.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── Source/
│ │ ├── .gitignore
│ │ ├── Package.swift
│ │ └── Sources/
│ │ └── Source/
│ │ └── Source.swift
│ ├── Module Export - Quick SFImage/
│ │ ├── .ActionManifest.plist
│ │ ├── .gitignore
│ │ ├── .supplement/
│ │ │ ├── Binary/
│ │ │ │ └── CommandLineBridge/
│ │ │ │ ├── CommandLineBridge/
│ │ │ │ │ └── main.swift
│ │ │ │ └── CommandLineBridge.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── CommandLineBridge.xcscheme
│ │ │ ├── Communicator/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Communicator/
│ │ │ │ ├── Communicator.h
│ │ │ │ ├── Communicator.m
│ │ │ │ └── include/
│ │ │ │ └── Communicator.h
│ │ │ ├── Definition/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Definition/
│ │ │ │ └── Definition.swift
│ │ │ ├── compile.sh
│ │ │ └── launch.sh
│ │ ├── App.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── Source/
│ │ ├── .gitignore
│ │ ├── Package.swift
│ │ └── Sources/
│ │ └── Source/
│ │ └── Source.swift
│ └── Module Export - Speak Dictionary/
│ ├── .ActionManifest.plist
│ ├── .gitignore
│ ├── .supplement/
│ │ ├── Binary/
│ │ │ └── CommandLineBridge/
│ │ │ ├── CommandLineBridge/
│ │ │ │ └── main.swift
│ │ │ └── CommandLineBridge.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── CommandLineBridge.xcscheme
│ │ ├── Communicator/
│ │ │ ├── .gitignore
│ │ │ ├── Package.swift
│ │ │ └── Sources/
│ │ │ └── Communicator/
│ │ │ ├── Communicator.h
│ │ │ ├── Communicator.m
│ │ │ └── include/
│ │ │ └── Communicator.h
│ │ ├── Definition/
│ │ │ ├── .gitignore
│ │ │ ├── Package.swift
│ │ │ └── Sources/
│ │ │ └── Definition/
│ │ │ └── Definition.swift
│ │ ├── compile.sh
│ │ └── launch.sh
│ ├── App.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── Source/
│ ├── .gitignore
│ ├── Package.swift
│ └── Sources/
│ └── Source/
│ └── Source.swift
├── ModuleTemplate/
│ ├── .templates
│ ├── Executable/
│ │ ├── ActionBeeModule.exec
│ │ └── Put your binary here
│ ├── ExecutableSwift/
│ │ ├── .gitignore
│ │ ├── .supplement/
│ │ │ ├── Binary/
│ │ │ │ └── CommandLineBridge/
│ │ │ │ ├── CommandLineBridge/
│ │ │ │ │ └── main.swift
│ │ │ │ └── CommandLineBridge.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── CommandLineBridge.xcscheme
│ │ │ ├── Communicator/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Package.swift
│ │ │ │ └── Sources/
│ │ │ │ └── Communicator/
│ │ │ │ ├── Communicator.h
│ │ │ │ ├── Communicator.m
│ │ │ │ └── include/
│ │ │ │ └── Communicator.h
│ │ │ └── Definition/
│ │ │ ├── .gitignore
│ │ │ ├── Package.swift
│ │ │ └── Sources/
│ │ │ └── Definition/
│ │ │ └── Definition.swift
│ │ ├── App.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ ├── Source/
│ │ │ ├── .gitignore
│ │ │ ├── Package.swift
│ │ │ └── Sources/
│ │ │ └── Source/
│ │ │ └── Source.swift
│ │ └── compile.command
│ ├── SourceNode/
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── .supplement/
│ │ │ └── compile.sh
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── global.d.ts
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── SourcePython/
│ │ └── main.py
│ └── SourceSwift/
│ ├── .gitignore
│ ├── .supplement/
│ │ ├── Binary/
│ │ │ └── CommandLineBridge/
│ │ │ ├── CommandLineBridge/
│ │ │ │ └── main.swift
│ │ │ └── CommandLineBridge.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── CommandLineBridge.xcscheme
│ │ ├── Communicator/
│ │ │ ├── .gitignore
│ │ │ ├── Package.swift
│ │ │ └── Sources/
│ │ │ └── Communicator/
│ │ │ ├── Communicator.h
│ │ │ ├── Communicator.m
│ │ │ └── include/
│ │ │ └── Communicator.h
│ │ ├── Definition/
│ │ │ ├── .gitignore
│ │ │ ├── Package.swift
│ │ │ └── Sources/
│ │ │ └── Definition/
│ │ │ └── Definition.swift
│ │ ├── compile.sh
│ │ └── launch.sh
│ ├── App.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── Source/
│ ├── .gitignore
│ ├── Package.swift
│ └── Sources/
│ └── Source/
│ └── Source.swift
└── Scripts/
├── NewlineDeduplicate.swift
├── PackTemplates.sh
├── UpdateGitHub.sh
└── UpdateLicenses.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
*.ActionTemplatePackage
================================================
FILE: .gitmodules
================================================
[submodule "External/Colorful"]
path = External/Colorful
url = https://github.com/Lakr233/Colorful
[submodule "External/AuxiliaryExecute"]
path = External/AuxiliaryExecute
url = https://github.com/Lakr233/AuxiliaryExecute
[submodule "External/SymbolPicker"]
path = External/SymbolPicker
url = https://github.com/xnth97/SymbolPicker
[submodule "External/KeychainAccess"]
path = External/KeychainAccess
url = https://github.com/kishikawakatsumi/KeychainAccess
================================================
FILE: .root
================================================
================================================
FILE: App/Action/Action/Action.entitlements
================================================
================================================
FILE: App/Action/Action/Application/Action.entitlements
================================================
================================================
FILE: App/Action/Action/Application/ActionApp.swift
================================================
//
// ActionApp.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import SwiftUI
@main
struct ActionApp: App {
static let bootTime: Date = .init()
@AppStorage("wiki.qaq.agreeToLicense")
static var agreeToLicense: Bool = false
static let documentDirectory: URL = {
let availableDirectories = FileManager
.default
.urls(for: .documentDirectory, in: .userDomainMask)
#if DEBUG
return availableDirectories[0]
.appendingPathComponent("ActionBee.Debug")
#else
return availableDirectories[0]
.appendingPathComponent("ActionBee")
#endif
}()
init() {
_ = ActionApp.bootTime
applicationSetup()
}
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
MainView()
}
.windowToolbarStyle(.unifiedCompact)
.commands { SidebarCommands() }
.commands { CommandGroup(replacing: CommandGroupPlacement.newItem) {} }
}
}
================================================
FILE: App/Action/Action/Application/AppDelegate.swift
================================================
//
// AppDelegate.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import AppKit
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate {
func switchDockIconMode() {
let windowCount = NSApp
.windows
.filter { self.filteringSpecialWindow($0) }
.count
if !StatusBarManager.shared.hasWindowOpened,
windowCount == 0,
!Menubar.shared.popover.isShown
{
NSApp.setActivationPolicy(.accessory)
} else {
NSApp.setActivationPolicy(.regular)
}
}
private func filteringSpecialWindow(_ window: NSWindow) -> Bool {
let list = ["NSStatusBarWindow", "_NSPopoverWindow"]
for item in list {
guard let clz = NSClassFromString(item) else { continue }
if window.isKind(of: clz.self) { return false }
}
return true
}
}
================================================
FILE: App/Action/Action/Application/AppSetup.swift
================================================
//
// ApplicationSetup.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import AppKit
extension ActionApp {
static let appBundleIdentifier: String = Bundle
.main
.bundleIdentifier ?? "wiki.qaq.unknown"
static let appVersion: String =
Bundle
.main
.infoDictionary?["CFBundleShortVersionString"] as? String
?? "unknown"
func applicationSetup() {
assert(Thread.isMainThread)
assert(getuid() != 0)
print(
"""
\(ActionApp.appBundleIdentifier) - \(ActionApp.appVersion)
Location:
[*] \(Bundle.main.bundleURL.path)
[*] \(Self.documentDirectory.path)
Environment: uid \(getuid()) gid \(getgid())
"""
)
disableDebuggerIfNeeded()
_ = AXUIElementCreateSystemWide()
_ = Executor.shared
_ = PasteboardManager.shared
_ = StatusBarManager.shared
let timer = Timer(timeInterval: 0.5, repeats: true) { _ in
appDelegate.switchDockIconMode()
}
RunLoop.current.add(timer, forMode: .common)
#if DEBUG
let debuggerTimer = Timer(timeInterval: 1, repeats: true) { _ in
_ = 0
}
RunLoop.current.add(debuggerTimer, forMode: .common)
#endif
}
private func disableDebuggerIfNeeded() {
#if !DEBUG
do {
typealias ptrace = @convention(c) (_ request: Int, _ pid: Int, _ addr: Int, _ data: Int) -> AnyObject
let open = dlopen("/usr/lib/system/libsystem_kernel.dylib", RTLD_NOW)
if unsafeBitCast(open, to: Int.self) > 0x1024 {
let result = dlsym(open, "ptrace")
if let result = result {
let target = unsafeBitCast(result, to: ptrace.self)
_ = target(0x1F, 0, 0, 0)
}
}
}
#endif
}
}
================================================
FILE: App/Action/Action/Application/Assets.xcassets/AccentColor.colorset/Contents.json
================================================
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.227",
"green" : "0.533",
"red" : "0.910"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.455",
"green" : "0.659",
"red" : "0.910"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: App/Action/Action/Application/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"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"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: App/Action/Action/Application/Assets.xcassets/Avatar.imageset/Contents.json
================================================
{
"images" : [
{
"filename" : "Avatar.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: App/Action/Action/Application/Assets.xcassets/Contents.json
================================================
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: App/Action/Action/Application/License.txt
================================================
MIT License
Copyright (c) 2022 Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==========
AuxiliaryExecute
MIT License
Copyright (c) 2021 Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==========
Colorful
MIT License
Copyright (c) 2021 Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==========
KeychainAccess
The MIT License (MIT)
Copyright (c) 2014 kishikawa katsumi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==========
SymbolPicker
MIT License
Copyright (c) 2022 Yubo Qin & Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==========
Updated: 2022-08-30
================================================
FILE: App/Action/Action/Application/en.lproj/Localizable.strings
================================================
/*
Localizable.strings
Action
Created by 维安雨轩 on 2022/08/19.
*/
================================================
FILE: App/Action/Action/Application/zh-Hans.lproj/Localizable.strings
================================================
/*
Localizable.strings
Action
Created by 维安雨轩 on 2022/08/19.
*/
//ModuleManageView.swift
"Create an action by click plus button on toolbar to process your pasteboard event. Format text, clean up links, speak when copy from special app, send to your device, etc etc. Choose an language you are familiar with to get start." = "通过点击工具栏上的加号按钮创建一个自动化来处理你的剪贴板事件。\n如格式化文本、清理链接或从设定应用中复制时,发送至你的设备等。\n现在快选择一种你熟悉的语言来开始吧。";
"Add Action" = "添加自动化模块";
"Import Action" = "导入自动化模块";
"Module" = "模块";
"You are about to import an Action Module which is untrusted with no signature. Importing malicious modules can pose unknown risks and there is no sandbox nor container dealing with it." = "你正在导入一个没有签名的不受信任的自动化模块。导入恶意模块可能会带来未知风险,在运行这个模块时并不会通过沙盒或容器来处理它。";
"Trust And Import" = "信任并导入";
"Cancel" = "取消";
"Failed to import this module" = "导入模块失败";
// ModuleImportView.swift
"You are about to import an untrusted module" = "您正在导入一个不受信任的模块";
"Importing malicious module may damage your system, you are in charge to review this module." = "导入恶意模块可能会损坏你的系统,您需要负责审查这个模块。";
"Trust & Import" = "信任并导入";
"OK" = "成功";
// ModuleElementView.swift
"Error" = "出错了";
// ModuleCreateView.swift
"Create Action" = "创建自动化模块";
"Module Name" = "模块名称";
"Language" = "语言";
"Next" = "继续";
// ModuleEditView.swift
"Edit Action" = "编辑自动化模块";
"Save" = "保存";
"Compiling Source" = "正在编译模块...";
"Compile Finished" = "编译完成";
"Broken Module" = "损坏的模块";
"Delete" = "删除";
"Close" = "关闭";
"Enabled" = "启用";
"Name" = "名称";
"Timeout: " = "超时:";
"Enable In App" = "在应用程序中启用";
"Enabled for All Apps" = "为所有应用程序启用";
"This pasteboard action will only run if copying from these apps" = "此自动化只有在从这些应用程序复制时才会运行";
"Coding" = "编辑";
"Edit Code" = "编辑代码";
"Show in Finder" = "在 Finder 中显示";
"Export" = "导出";
"Module Template: %@" = "模板: %@";
"Unknown" = "未知";
"No Build Hint" = "没有构建提示";
"You should recompile, click save, this module each time you edit it" = "在每次编辑该模块时,点击保存将会重新编译。";
"Unable to compile this action: %@" = "无法编译这个自动化模块: %@";
"Are you sure you want to delete this module? This operation can not be undone." = "您确定要删除这个模块吗?\n确定后将无法撤销。";
"Select Application" = "选择应用程序";
"Failed to load this module" = "加载此模块失败";
"Module Export - %@" = "导出模块 - %@";
"Unnamed" = "未命名";
// ContentView.swift
"Toggle Sidebar" = "切换侧边栏";
// SidebarView.swift
"App" = "应用";
"Welcome" = "欢迎";
"Action" = "自动化";
"Module" = "模块";
"History" = "历史";
"Misc" = "其他";
"Setting" = "设置";
"Diagnostic" = "诊断";
// WelcomeView.swift
"Welcome to Action Bee" = "欢迎使用 Action Bee";
"A programmable pasteboard action trigger." = "一个可编程的剪贴板触发器";
// HistoryView.swift
"No History Was Found" = "暂无历史记录";
"Clear History" = "清除历史记录";
"Are you sure you want to delete all history records? This operation can not be undone." = "你确定要删除所有历史记录吗?\n确定后将无法撤销。";
"Pasteboard Event" = "剪贴板事件";
"Length: %lld Action Candidates: %lld" = "剪贴长度: %lld 共执行模块: %lld";
"Deleted Action" = "被删除的动作";
" Post Action: %@" = " 动作: %@";
" Content: %@" = " 内容: %@";
// SettingView.swift
"Pasteboard Deduplicate" = "阻拦重复执行";
"Pasteboard content matches previous will not generate event if on" = "如剪贴板的内容与之前的相匹配,开启后,将不会执行事件。";
"Silent Mode" = "静默模式";
"Do not show popover after action triggered" = "动作触发后不弹出窗口";
"Toast Mode" = "Toast 模式";
"Use toast instead of popover on menubar" = "在屏幕上显示简易提示框而不是弹出式菜单";
"Reduced UI Effects" = "减少 UI 视觉效果";
"Turning off visual effects does not affect app's core functionality" = "关闭视觉效果并不会影响应用程序的核心功能";
"Application" = "应用";
"Get Source Code" = "获取源代码";
"License" = "许可证";
// MenubarView.swift
"ActionBee is ready to accept pasteboard events." = "ActionBee 已准备好处理剪贴板事件。";
// LicenseView.swift
"Software License" = "软件许可证";
"I understand and agree to this license." = "我理解并同意此许可。";
"Done" = "同意";
================================================
FILE: App/Action/Action/Backend/Action/ActionManager+Artifact.swift
================================================
//
// ActionManager+Artifact.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import Foundation
private let artifactPathExtension = "ActionBeeArtifact"
extension ActionManager {
struct ModuleArtifact: Codable {
let id: Action.ID
let signature: String
init?(id: Action.ID, copyingArtifactAt atUrl: URL) {
self.id = id
let targetDir = Self.obtainArtifactUrlForAction(withId: id)
do {
try? FileManager.default.removeItem(at: targetDir)
var isDir = ObjCBool(false)
guard FileManager.default.fileExists(atPath: atUrl.path, isDirectory: &isDir) else {
return nil
}
if isDir.boolValue {
try FileManager.default.copyItem(at: atUrl, to: targetDir)
} else {
try FileManager.default.createDirectory(at: targetDir, withIntermediateDirectories: true)
let name = atUrl.lastPathComponent
let target = targetDir.appendingPathComponent(name)
try FileManager.default.copyItem(at: atUrl, to: target)
}
signature = try Self.generatePackageSignature(at: targetDir)
} catch {
print("[E] \(error.localizedDescription)")
return nil
}
}
static func deletingDotFiles(at atUrl: URL) throws {
let enumerator = FileManager.default.enumerator(atPath: atUrl.path)
while let subPath = enumerator?.nextObject() as? String {
let url = atUrl.appendingPathComponent(subPath)
var shouldClean = false
if subPath == ".DS_Store" { shouldClean = true }
if subPath.hasPrefix("._") { shouldClean = true }
if shouldClean {
print("[*] deleting dot files inside artifact \(url.path)")
try FileManager.default.removeItem(at: url)
}
}
}
static func generatePackageSignature(at atUrl: URL) throws -> String {
try deletingDotFiles(at: atUrl)
var signatureDic = [String: String]()
let enumerator = FileManager.default.enumerator(atPath: atUrl.path)
while let subPath = enumerator?.nextObject() as? String {
let path = atUrl.appendingPathComponent(subPath)
var isDir = ObjCBool(false)
guard FileManager
.default
.fileExists(atPath: path.path, isDirectory: &isDir)
else {
throw GenericActionError.brokenResources
}
let data = try Data(contentsOf: path)
let hash = data.sha256()
signatureDic[subPath] = hash
}
var hasher = String()
let valueArray = signatureDic.sorted { $0.key < $1.key }
for (key, value) in valueArray {
hasher += key
hasher += value
hasher += "\n"
}
guard let signature = hasher.data(using: .utf8)?.sha256() else {
throw GenericActionError.unknown
}
return signature
}
static func obtainArtifactUrlForAction(withId: Action.ID) -> URL {
ActionManager.shared
.actionArtifactBaseUrl
.appendingPathComponent(withId.uuidString)
.appendingPathExtension(artifactPathExtension)
}
func obtainArtifactUrl() -> URL {
Self.obtainArtifactUrlForAction(withId: id)
}
func validateSignature() -> Bool {
do {
let testSignature = try Self.generatePackageSignature(at: obtainArtifactUrl())
return signature == testSignature
} catch {
print("[E] \(error.localizedDescription)")
return false
}
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionManager+Event.swift
================================================
//
// ActionManager+Event.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import Cocoa
import Foundation
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
extension ActionManager {
struct ActionRecipeData: Codable {
let postAction: PostAction
let postContent: String
let continueQueue: Bool
enum PostAction: String, Codable {
case overwrite
case speak
case none
func humanReadableDescription() -> String {
switch self {
case .overwrite: return "Overwrite Pasteboard"
case .speak: return "Speak Message"
case .none: return "None"
}
}
}
init(postAction: PostAction, postContent: String, continueQueue: Bool) {
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
}
func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
static func retrieve(withData data: Data) -> Self? {
try? decoder.decode(Self.self, from: data)
}
}
func handle(pasteboardEvent event: PasteboardManager.PEvent) {
assert(!Thread.isMainThread)
var actionCandidates: [Action] = []
DispatchQueue.withMainAndWait {
actionCandidates = self.actions
}
actionCandidates = actionCandidates
.filter { enabledActions.contains($0.id) }
.filter { !initialingAciton.contains($0.id) }
.filter {
if $0.enabledAppList.isEmpty {
return true
}
guard let appBundleIdentifier = event.app?.bundleIdentifier else {
return false
}
return $0.enabledAppList.contains(appBundleIdentifier)
}
.sorted { a, b in
guard a.priority == b.priority else {
return a.priority < b.priority
}
return a.name < b.name
}
guard !actionCandidates.isEmpty else {
print("[-] no action candidate found, ignoring pasteboard event")
return
}
print("[*] pasteboard event resolved \(actionCandidates.count) candidates")
DispatchQueue.withMainAndWait {
self.actionRunning = true
self.actionRunningHint = "Resolved \(actionCandidates.count) Action Candidates"
Menubar.shared.switchTitle(status: .running)
}
var successAction: [HistoryElement.SuccessRecord] = []
var failedAction: [HistoryElement.FailureRecord] = []
var shouldShowResultWindow = false
defer {
let history = HistoryElement(
event: event,
actionCandidates: actionCandidates.map(\.id),
succeedAction: successAction,
failedAction: failedAction
)
DispatchQueue.withMainAndWait {
self.histories.append(history)
self.actionRunning = false
self.actionRunningHint = ""
Menubar.shared.switchTitle(status: .ready)
if shouldShowResultWindow, !Config.shared.silentMode {
if Config.shared.toastMode {
var image = "checkmark.circle.fill"
if !failedAction.isEmpty {
image = "checkmark.circle.trianglebadge.exclamationmark"
}
Toast.post(systemIcon: image, message: "ActionBee Completed")
} else {
Menubar.shared.showPopover()
}
}
}
}
for action in actionCandidates {
DispatchQueue.withMainAndWait {
self.actionRunningHint = "Executing Action - \(action.name)"
}
let recipe = action.template
.obtainTemplateDetails()
.executeModule(
id: action.id,
withPasteboardEvent: event
) { print($0) }
switch recipe {
case let .success(recipe):
successAction.append(.init(
action: action.id,
recipeAction: recipe.postAction.humanReadableDescription(),
recipeContent: recipe.postContent
))
resolvePostAction(recipe)
if recipe.postAction != .none { shouldShowResultWindow = true }
guard recipe.continueQueue else { return }
case let .failure(failure):
shouldShowResultWindow = true
failedAction.append(.init(action: action.id, errorHint: failure.message))
print("[E] error executing aciton: \(failure.message)")
continue
}
}
}
func resolvePostAction(_ object: ActionRecipeData) {
assert(!Thread.isMainThread)
switch object.postAction {
case .none: break
case .speak:
DispatchQueue.global().async {
Executor.shared.speak(object.postContent)
}
case .overwrite:
NSPasteboard.general.prepareForNewContents()
NSPasteboard.general.setString(object.postContent, forType: .string)
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionManager+History.swift
================================================
//
// ActionManager+History.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import Foundation
extension ActionManager {
struct HistoryElement: Codable, Identifiable, Hashable, Equatable {
var id: UUID = .init()
let date: Date
let event: PasteboardManager.PEvent
let actionCandidates: [Action.ID]
struct SuccessRecord: Codable, Identifiable, Hashable, Equatable {
var id: UUID = .init()
let action: Action.ID
let recipeAction: String
let recipeContent: String
}
let succeedAction: [SuccessRecord]
struct FailureRecord: Codable, Identifiable, Hashable, Equatable {
var id: UUID = .init()
let action: Action.ID
let errorHint: String
}
let failedAction: [FailureRecord]
init(
id: UUID = .init(),
date: Date = .init(),
event: PasteboardManager.PEvent,
actionCandidates: [ActionManager.Action.ID] = [],
succeedAction: [ActionManager.HistoryElement.SuccessRecord] = [],
failedAction: [ActionManager.HistoryElement.FailureRecord] = []
) {
self.id = id
self.date = date
self.event = event
self.actionCandidates = actionCandidates
self.succeedAction = succeedAction
self.failedAction = failedAction
}
func search(with key: String) -> Bool {
if event.app?.name.lowercased().contains(key) ?? false { return true }
if event.app?.bundleIdentifier.lowercased().contains(key) ?? false { return true }
if event.content.lowercased().contains(key) { return true }
if date.formatted(date: .complete, time: .complete).lowercased().contains(key) {
return true
}
return false
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionManager+Module.swift
================================================
//
// ActionManager+Module.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import Foundation
/*
Action will be compiled into ActionManifest.plist
into project root dir
so the project dir looks like: eg swift
.
├── .build
│ └── cli <- binary
├── App.xcworkspace
└── compile.sh <- emit binary, called each time when compile
// user editable
├── Source
│ ├── Package.swift
│ └── Sources
│ └── Source
│ └── Source.swift <- user code
// program granted
├── .ActionManifest.plist <- exported definition of this action
*/
extension ActionManager {
struct Action: Codable, Equatable, Hashable, Identifiable {
var id: UUID
var name: String
var icon: String
var priority: Int // lower first-er P0~
var timeout: Int
var template: ActionManager.ModuleTemplateIdentifier
// will only run if copy from these apps
var enabledAppList: [String] = []
// keep for future usage
var attachment: [String: String]
init(
id: UUID = .init(),
name: String,
icon: String = "text.append",
priority: Int = 100,
timeout: Int = 5,
template: ActionManager.ModuleTemplateIdentifier,
enabledAppList: [String] = [],
attachment: [String: String] = [:]
) {
self.id = id
self.name = name
self.icon = icon
self.priority = priority
self.timeout = timeout
self.template = template
self.enabledAppList = enabledAppList
self.attachment = attachment
}
}
func updateActionModuleManifest(onActionId: Action.ID? = nil) {
if let id = onActionId {
guard let action = self[id] else {
return
}
try? compileManifestAndSave(forAction: action)
}
for action in actions {
try? compileManifestAndSave(forAction: action)
}
}
func compileManifestAndSave(forAction action: Action) throws {
let actionModuleDir = actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
let manifestUrl = actionModuleDir
.appendingPathComponent(actionManifestFileName)
.appendingPathExtension(actionManifestExtension)
guard FileManager.default.fileExists(atPath: actionModuleBaseUrl.path) else {
return
}
let data = try actionManifestEncoder.encode(action)
try data.write(to: manifestUrl, options: .atomic)
}
func deleteModule(withId id: Action.ID) {
print("[*] deleting module \(id)")
let moduleUrl = actionModuleBaseUrl
.appendingPathComponent(id.uuidString)
try? FileManager.default.removeItem(at: moduleUrl)
actions = actions.filter { $0.id != id }
enabledActions = enabledActions.filter { $0 != id }
invalidateArtifactCache(forAction: id)
}
func issueCompile(forAction actionId: Action.ID, output: @escaping (String) -> Void) -> Result {
assert(!Thread.isMainThread)
guard let action = self[actionId] else {
return .failure(.brokenResources)
}
let result = action.template
.obtainTemplateDetails()
.compileModule(id: actionId, output: output)
return result
}
func registerArtifact(forAction actionId: Action.ID, artifact: URL) {
print("[*] copying artifact at path \(artifact.path) for action \(actionId)")
try? FileManager.default.createDirectory(
at: ActionManager.shared.actionArtifactBaseUrl,
withIntermediateDirectories: true
)
guard let object = ModuleArtifact(id: actionId, copyingArtifactAt: artifact) else {
return
}
print("[*] registering artifact \(actionId) with signature \(object.signature)")
guard Thread.isMainThread else {
DispatchQueue.withMainAndWait {
self.artifacts[object.id] = object
}
return
}
artifacts[object.id] = object
}
func invalidateArtifactCache(forAction actionId: Action.ID) {
print("[*] invalidating artifact cache for \(actionId)")
if let value = artifacts[actionId] {
try? FileManager.default.removeItem(at: value.obtainArtifactUrl())
}
if Thread.isMainThread {
artifacts.removeValue(forKey: actionId)
} else {
DispatchQueue.withMainAndWait {
self.artifacts.removeValue(forKey: actionId)
}
}
}
func importModule(at: URL) -> Result {
print("[*] importing module at \(at.path)")
let manifest = at
.appendingPathComponent(actionManifestFileName)
.appendingPathExtension(actionManifestExtension)
do {
let data = try Data(contentsOf: manifest)
let action = try actionManifestDecoder.decode(Action.self, from: data)
let target = actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
print("[*] manifest returns id \(action.id)")
try? FileManager.default.removeItem(at: target)
try FileManager.default.copyItem(at: at, to: target)
invalidateArtifactCache(forAction: action.id)
DispatchQueue.withMainAndWait {
self[action.id] = action
self.enabledActions.append(action.id)
}
updateActionModuleManifest(onActionId: action.id)
return .success(action.id)
} catch {
return .failure(error)
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionManager.swift
================================================
//
// ActionManager.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import Combine
import Foundation
final class ActionManager: ObservableObject {
static let shared = ActionManager()
private init() {
#if DEBUG
for item in ModuleTemplateIdentifier.allCases {
_ = item.obtainTemplateDetails().getTemplateBundleURL()
}
#endif
var buildAction: [Action.ID: Action] = [:]
for action in actionsStore {
buildAction[action.id] = action
}
// now clean the items inside the dir if not exists in plist
do {
let actionIds = buildAction.keys.map(\.uuidString)
let list = (
try? FileManager
.default
.contentsOfDirectory(atPath: actionModuleBaseUrl.path)
) ?? []
var deleteList = [String]()
deleteList += list.filter { !actionIds.contains($0) }
deleteList += actionIds.filter { !list.contains($0) }
for element in deleteList {
let url = actionModuleBaseUrl.appendingPathComponent(element)
try? FileManager.default.removeItem(at: url)
if let id = UUID(uuidString: element) {
buildAction.removeValue(forKey: id)
}
print("[-] removing unregistered action module file at path \(url.path)")
}
}
actions = buildAction.values
.sorted { $0.name < $1.name }
updateActionModuleManifest()
enabledActions = Array(Set(enabledActionsStore))
for action in actions {
print("[+] loading module \(action.name) - \(action.id.uuidString)")
}
artifacts = artifactsStore
for artifact in artifacts {
let found = actions.contains { $0.id == artifact.key }
if found {
print("[+] loading artifact \(artifact.key.uuidString)")
DispatchQueue.global().async {
guard artifact.value.validateSignature() else {
print("[E] artifact signature mismatch!")
self.invalidateArtifactCache(forAction: artifact.key)
return
}
}
} else {
DispatchQueue.global().async {
self.invalidateArtifactCache(forAction: artifact.key)
}
}
}
histories = historiesStore
.sorted { $0.date < $1.date }
}
var actionModuleBaseUrl: URL {
let ret = ActionApp
.documentDirectory
.appendingPathComponent("ActionModules")
try? FileManager.default.createDirectory(
at: ret,
withIntermediateDirectories: true
)
return ret
}
var actionArtifactBaseUrl: URL {
let ret = ActionApp
.documentDirectory
.appendingPathComponent("ActionArtifact")
try? FileManager.default.createDirectory(
at: ret,
withIntermediateDirectories: true
)
return ret
}
let actionManifestFileName = ".ActionManifest"
let actionManifestExtension = "plist"
let actionManifestEncoder = PropertyListEncoder()
let actionManifestDecoder = PropertyListDecoder()
@EncryptedCodableDefaultsWrapper(key: "wiki.qaq.ActionManager.actionsStoreKey", defaultValue: [Action]())
private var actionsStore
@Published var actions: [Action] = [] {
didSet { DispatchQueue.global().async { self.actionsStore = self.actions } }
}
@Published var initialingAciton: Set = []
subscript(actionId: UUID) -> Action? {
get {
actions.first { $0.id == actionId }
}
set {
assert(Thread.isMainThread)
guard let newValue = newValue else {
deleteModule(withId: actionId)
return
}
let idx = actions.firstIndex { $0.id == newValue.id }
if let idx = idx {
actions[idx] = newValue
} else {
actions = (
actions + [newValue]
)
.sorted { $0.name < $1.name }
}
}
}
@EncryptedCodableDefaultsWrapper(key: "wiki.qaq.ActionManager.enabledActions", defaultValue: [])
private var enabledActionsStore: [Action.ID]
@Published var enabledActions = [Action.ID]() {
didSet { DispatchQueue.global().async { self.enabledActionsStore = self.enabledActions } }
}
@EncryptedCodableDefaultsWrapper(key: "wiki.qaq.ActionManager.artifactsStore", defaultValue: [Action.ID: ModuleArtifact]())
private var artifactsStore
@Published var artifacts: [Action.ID: ModuleArtifact] = [:] {
didSet { DispatchQueue.global().async { self.artifactsStore = self.artifacts } }
}
@EncryptedCodableDefaultsWrapper(key: "wiki.qaq.ActionManager.historiesStore", defaultValue: [HistoryElement]())
private var historiesStore
@Published var histories: [HistoryElement] = [] {
didSet {
let historyLimit = 500
guard histories.count < historyLimit else {
DispatchQueue.main.async {
self.histories.removeFirst(self.histories.count - historyLimit)
}
return
}
DispatchQueue.global().async { self.historiesStore = self.histories }
}
}
@Published var actionRunning = false
@Published var actionRunningHint = ""
}
================================================
FILE: App/Action/Action/Backend/Action/ActionModuleTemplates/ActionManager+Template.swift
================================================
//
// ActionManager+ModuleTemplate.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import Cocoa
import Foundation
protocol ModuleTemplate {
func getLanguage() -> String
func getTemplateBundleName() -> String
func getBuildHint() -> String
func getTemplateBundleURL() -> URL
func openDesignatedEditor(id: ActionManager.Action.ID) -> Result
func compileModule(
id: ActionManager.Action.ID,
output: @escaping (String) -> Void
) -> Result
func executeModule(
id: ActionManager.Action.ID,
withPasteboardEvent event: PasteboardManager.PEvent,
output: @escaping (String) -> Void
) -> Result
}
extension ModuleTemplate {
func getTemplateBundleURL() -> URL {
Bundle.main.url(
forResource: getTemplateBundleName(),
withExtension: "ActionTemplatePackage",
subdirectory: "ActionTemplates"
)!
}
}
extension ActionManager {
enum GenericActionError: Error {
case permissionDenied
case compilerError
case brokenResources
case designatedEditorMissing
case unauthorizedModificationDetected
case invalidResponse
case unknown
var message: String {
switch self {
case .permissionDenied: return "Permission denied for requires resources."
case .compilerError: return "Compiler returned an error, check your source."
case .brokenResources: return "Resources for this module was not found."
case .designatedEditorMissing: return "The designated editor app for this module was not found, please edit it in Finder yourself."
case .unauthorizedModificationDetected: return "The requires resource was modified by unauthorized event."
case .invalidResponse: return "Invalid respond."
case .unknown: return "Unknown error occurred."
}
}
}
enum ModuleTemplateIdentifier: String, Codable, CaseIterable, Hashable, Equatable {
case executable
case executableSwift
case swift
case node
case python
func obtainTemplateDetails() -> ModuleTemplate {
switch self {
case .executable: return ModuleTemplateExecutable()
case .executableSwift: return ModuleTemplateExecutableSwift()
case .swift: return ModuleTemplateSwift()
case .node: return ModuleTemplateNode()
case .python: return ModuleTemplatePython()
}
}
}
func createAction(withName name: String, withModuleTemplate template: ModuleTemplateIdentifier) -> UUID? {
let actionUUID = UUID()
let templateBundleUrl = template
.obtainTemplateDetails()
.getTemplateBundleURL()
let extractTarget = actionModuleBaseUrl
.appendingPathComponent(actionUUID.uuidString)
let action = Action(id: actionUUID, name: name, template: template)
print("[*] creating module at \(extractTarget.path)")
do {
try FileManager.default.createDirectory(at: extractTarget, withIntermediateDirectories: true)
try Executor.shared.unarchiveTar(at: templateBundleUrl, toDest: extractTarget)
try compileManifestAndSave(forAction: action)
} catch {
return nil
}
DispatchQueue.withMainAndWait {
self.actions = (
self.actions + [action]
)
.sorted { $0.name < $1.name }
self.enabledActions.append(action.id)
}
return actionUUID
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionModuleTemplates/Template+Executable.swift
================================================
//
// Template+Executable.swift
// Action
//
// Created by Lakr Aream on 2022/8/17.
//
import AuxiliaryExecute
import Cocoa
import Foundation
extension ActionManager {
class ModuleTemplateExecutable: ModuleTemplate {
func getLanguage() -> String { "Binary Executable" }
func getTemplateBundleName() -> String { "Executable" }
func getBuildHint() -> String { "Compile your binary, name it ActionBeeModule.exec, and put it here." }
struct ArgumentData: Codable {
let focusAppID: String?
let focusAppName: String?
let pasteboardContent: String
init(focusAppID: String?, focusAppName: String?, pasteboardContent: String) {
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
}
func compileBase64() -> String? {
(try? JSONEncoder().encode(self))?.base64EncodedString()
}
}
func openDesignatedEditor(id: ActionManager.Action.ID) -> Result {
guard let action = ActionManager.shared[id] else {
return .failure(GenericActionError.brokenResources)
}
let target = ActionManager.shared.actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
guard FileManager.default.fileExists(atPath: target.path) else {
return .failure(GenericActionError.brokenResources)
}
guard NSWorkspace.shared.open(target) else {
return .failure(GenericActionError.designatedEditorMissing)
}
return .success
}
func compileModule(id: ActionManager.Action.ID, output _: @escaping (String) -> Void) -> Result {
assert(!Thread.isMainThread)
guard let action = ActionManager.shared[id] else {
return .failure(.brokenResources)
}
let target = ActionManager.shared.actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
.appendingPathComponent("ActionBeeModule.exec")
guard FileManager.default.fileExists(atPath: target.path) else {
return .failure(.brokenResources)
}
guard FileManager.default.isExecutableFile(atPath: target.path) else {
return .failure(.permissionDenied)
}
ActionManager.shared.registerArtifact(forAction: action.id, artifact: target)
return .success
}
func executeModule(id: ActionManager.Action.ID, withPasteboardEvent event: PasteboardManager.PEvent, output: @escaping (String) -> Void) -> Result {
assert(!Thread.isMainThread)
guard let action = ActionManager.shared[id],
let artifact = ActionManager.shared.artifacts[id]
else {
return .failure(.brokenResources)
}
guard artifact.validateSignature() else {
return .failure(.unauthorizedModificationDetected)
}
guard let argument = ArgumentData(
focusAppID: event.app?.bundleIdentifier,
focusAppName: event.app?.name,
pasteboardContent: event.content
)
.compileBase64()
else {
return .failure(.brokenResources)
}
print("[*] executing action \(id.uuidString)")
var resultData: ActionRecipeData?
let binary = artifact
.obtainArtifactUrl()
.appendingPathComponent("cli")
.path
let recipe = AuxiliaryExecute.spawn(
command: binary,
environment: ["Communicator_Message": argument],
timeout: Double(action.timeout),
output: output
)
var lastLine = recipe.stderr
.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: "\n")
.last?
.trimmingCharacters(in: .whitespaces)
?? ""
let prefix = "ActionBee-Result-Recipe://"
if lastLine.hasPrefix(prefix) {
lastLine.removeFirst(prefix.count)
}
if let base64 = Data(base64Encoded: lastLine) {
resultData = ActionRecipeData.retrieve(withData: base64)
}
guard let result = resultData else {
return .failure(.invalidResponse)
}
return .success(result)
}
}
class ModuleTemplateExecutableSwift: ModuleTemplateExecutable {
override func getLanguage() -> String { "Binary Executable - Swift" }
override func getTemplateBundleName() -> String { "ExecutableSwift" }
override func getBuildHint() -> String { "Compile your binary, name it ActionBeeModule.exec, and put it here." }
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionModuleTemplates/Template+Node.swift
================================================
//
// Template+Node.swift
// Action
//
// Created by Innei on 2022/8/21.
//
import AuxiliaryExecute
import Foundation
extension ActionManager {
class ModuleTemplateNode: ModuleTemplateExecutable {
override func getLanguage() -> String { "Source - Node" }
override func getTemplateBundleName() -> String { "SourceNode" }
override func getBuildHint() -> String { "To build Node Module, node and it's tool is required. Install them yourself." }
override func openDesignatedEditor(id: ActionManager.Action.ID) -> Result {
let url = ActionManager.shared
.actionModuleBaseUrl
.appendingPathComponent(id.uuidString)
let recipe = AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", "code \(url.path)"]
)
guard recipe.exitCode == 0 else {
return .failure(.designatedEditorMissing)
}
return .success
}
override func compileModule(id: ActionManager.Action.ID, output: @escaping (String) -> Void) -> Result {
guard let action = ActionManager.shared[id] else {
return .failure(.brokenResources)
}
let temporaryDir = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(UUID().uuidString)
try? FileManager.default.removeItem(at: temporaryDir)
defer {
try? FileManager.default.removeItem(at: temporaryDir)
}
do {
output("[*] starting compiler at \(temporaryDir.path)\n")
let userSrc = ActionManager.shared
.actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
let targetSrc = temporaryDir
output("[*] copying user source from \(userSrc.path) to \(targetSrc.path)\n")
try FileManager.default.copyItem(at: userSrc, to: targetSrc)
FileManager.default.createFile(
atPath: temporaryDir.appendingPathComponent(".action").path,
contents: nil
)
} catch {
output("[E] \(error.localizedDescription)")
return .failure(.permissionDenied)
}
output("[*] calling compiler script\n")
let compileScript = temporaryDir
.appendingPathComponent(".supplement")
.appendingPathComponent("compile.sh")
let recipe = executeZshScript(atLocation: compileScript, output: output)
guard recipe.exitCode == 0 else {
return .failure(.compilerError)
}
let artifactLocation = temporaryDir
.appendingPathComponent("dist")
// .appendingPathComponent("index.js")
guard FileManager.default.fileExists(atPath: artifactLocation.path) else {
return .failure(.permissionDenied)
}
output("[*] compiled binary at \(artifactLocation.path)\n")
ActionManager.shared.registerArtifact(forAction: action.id, artifact: artifactLocation)
return .success
}
override func executeModule(id: ActionManager.Action.ID, withPasteboardEvent event: PasteboardManager.PEvent, output: @escaping (String) -> Void) -> Result {
assert(!Thread.isMainThread)
guard let action = ActionManager.shared[id],
let artifact = ActionManager.shared.artifacts[id]
else {
return .failure(.brokenResources)
}
guard artifact.validateSignature() else {
return .failure(.unauthorizedModificationDetected)
}
let script = artifact
.obtainArtifactUrl()
.appendingPathComponent("index.js")
guard let argument = ArgumentData(
focusAppID: event.app?.bundleIdentifier,
focusAppName: event.app?.name,
pasteboardContent: event.content
)
.compileBase64()
else {
return .failure(.brokenResources)
}
print("[*] executing action \(id.uuidString)")
var resultData: ActionRecipeData?
let recipe = AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", "node \(script.path)"],
environment: ["Communicator_Message": argument],
timeout: Double(action.timeout),
output: output
)
var lastLine = recipe.stderr
.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: "\n")
.last?
.trimmingCharacters(in: .whitespaces)
?? ""
let prefix = "ActionBee-Result-Recipe://"
if lastLine.hasPrefix(prefix) {
lastLine.removeFirst(prefix.count)
}
if let base64 = Data(base64Encoded: lastLine) {
resultData = ActionRecipeData.retrieve(withData: base64)
}
guard let result = resultData else {
return .failure(.invalidResponse)
}
return .success(result)
}
func executeZshScript(atLocation: URL, output: @escaping (String) -> Void = { _ in }) -> AuxiliaryExecute.ExecuteRecipe {
AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", atLocation.path],
output: output
)
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionModuleTemplates/Template+Python.swift
================================================
//
// Template+Python.swift
// Action
//
// Created by Lakr Aream on 2022/8/30.
//
import AuxiliaryExecute
import Foundation
extension ActionManager {
class ModuleTemplatePython: ModuleTemplateExecutable {
override func getLanguage() -> String { "Source - Python" }
override func getTemplateBundleName() -> String { "SourcePython" }
override func getBuildHint() -> String { "To build Python Module, python 3 and it's tool is required. Install them yourself." }
override func openDesignatedEditor(id: ActionManager.Action.ID) -> Result {
let url = ActionManager.shared
.actionModuleBaseUrl
.appendingPathComponent(id.uuidString)
let recipe = AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", "code \(url.path)"]
)
guard recipe.exitCode == 0 else {
return .failure(.designatedEditorMissing)
}
return .success
}
override func compileModule(id: ActionManager.Action.ID, output _: @escaping (String) -> Void) -> Result {
guard let action = ActionManager.shared[id] else {
return .failure(.brokenResources)
}
let actionUrl = ActionManager.shared
.actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
ActionManager.shared.registerArtifact(forAction: action.id, artifact: actionUrl)
return .success
}
override func executeModule(id: ActionManager.Action.ID, withPasteboardEvent event: PasteboardManager.PEvent, output: @escaping (String) -> Void) -> Result {
assert(!Thread.isMainThread)
guard let action = ActionManager.shared[id],
let artifact = ActionManager.shared.artifacts[id]
else {
return .failure(.brokenResources)
}
guard artifact.validateSignature() else {
return .failure(.unauthorizedModificationDetected)
}
let script = artifact
.obtainArtifactUrl()
.appendingPathComponent("main.py")
guard let argument = ArgumentData(
focusAppID: event.app?.bundleIdentifier,
focusAppName: event.app?.name,
pasteboardContent: event.content
)
.compileBase64()
else {
return .failure(.brokenResources)
}
print("[*] executing action \(id.uuidString)")
var resultData: ActionRecipeData?
let recipe = AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", "python3 \(script.path)"],
environment: ["Communicator_Message": argument],
timeout: Double(action.timeout),
output: output
)
var lastLine = recipe.stderr
.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: "\n")
.last?
.trimmingCharacters(in: .whitespaces)
?? ""
let prefix = "ActionBee-Result-Recipe://"
if lastLine.hasPrefix(prefix) {
lastLine.removeFirst(prefix.count)
}
if let base64 = Data(base64Encoded: lastLine) {
resultData = ActionRecipeData.retrieve(withData: base64)
}
guard let result = resultData else {
return .failure(.invalidResponse)
}
return .success(result)
}
func executeZshScript(atLocation: URL, output: @escaping (String) -> Void = { _ in }) -> AuxiliaryExecute.ExecuteRecipe {
AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", atLocation.path],
output: output
)
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionModuleTemplates/Template+Swift.swift
================================================
//
// ModuleTemplate+Swift.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import AuxiliaryExecute
import Cocoa
extension ActionManager {
class ModuleTemplateSwift: ModuleTemplateExecutable {
override func getLanguage() -> String { "Source - Swift" }
override func getTemplateBundleName() -> String { "SourceSwift" }
override func getBuildHint() -> String { "To build Swift Module, Xcode and it's tool xcode-build is required. Install Xcode yourself." }
override func openDesignatedEditor(id: ActionManager.Action.ID) -> Result {
guard let action = ActionManager.shared[id] else {
return .failure(GenericActionError.brokenResources)
}
let target = ActionManager.shared.actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
.appendingPathComponent("App.xcworkspace")
guard FileManager.default.fileExists(atPath: target.path) else {
return .failure(GenericActionError.brokenResources)
}
guard NSWorkspace.shared.open(target) else {
return .failure(GenericActionError.designatedEditorMissing)
}
return .success
}
override func compileModule(id: ActionManager.Action.ID, output: @escaping (String) -> Void) -> Result {
assert(!Thread.isMainThread)
guard let action = ActionManager.shared[id] else {
return .failure(.brokenResources)
}
let temporaryDir = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(UUID().uuidString)
try? FileManager.default.removeItem(at: temporaryDir)
defer {
try? FileManager.default.removeItem(at: temporaryDir)
}
do {
output("[*] starting compiler at \(temporaryDir.path)\n")
try FileManager.default.createDirectory(at: temporaryDir, withIntermediateDirectories: true)
try Executor.shared.unarchiveTar(at: getTemplateBundleURL(), toDest: temporaryDir)
let validatedSourcePathComponents = "Source"
let userSrc = ActionManager.shared
.actionModuleBaseUrl
.appendingPathComponent(action.id.uuidString)
.appendingPathComponent(validatedSourcePathComponents)
let targetSrc = temporaryDir
.appendingPathComponent(validatedSourcePathComponents)
output("[*] copying user source from \(userSrc.path) to \(targetSrc.path)\n")
try FileManager.default.removeItem(at: targetSrc)
try FileManager.default.copyItem(at: userSrc, to: targetSrc)
FileManager.default.createFile(
atPath: temporaryDir.appendingPathComponent(".action").path,
contents: nil
)
} catch {
output("[E] \(error.localizedDescription)")
return .failure(.permissionDenied)
}
output("[*] calling compiler script\n")
let compileScript = temporaryDir
.appendingPathComponent(".supplement")
.appendingPathComponent("compile.sh")
let recipe = executeZshScript(atLocation: compileScript, output: output)
guard recipe.exitCode == 0 else {
return .failure(.compilerError)
}
let binaryLocation = temporaryDir
.appendingPathComponent(".build")
.appendingPathComponent("cli")
guard FileManager.default.fileExists(atPath: binaryLocation.path) else {
return .failure(.permissionDenied)
}
output("[*] compiled binary at \(binaryLocation.path)\n")
ActionManager.shared.registerArtifact(forAction: action.id, artifact: binaryLocation)
return .success
}
func executeZshScript(atLocation: URL, output: @escaping (String) -> Void = { _ in }) -> AuxiliaryExecute.ExecuteRecipe {
AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", atLocation.path],
output: output
)
}
}
}
================================================
FILE: App/Action/Action/Backend/Action/ActionTemplates/.templates
================================================
================================================
FILE: App/Action/Action/Backend/Config/Config.swift
================================================
//
// Config.swift
// Action
//
// Created by Lakr Aream on 2022/8/17.
//
import Combine
import Foundation
class Config: ObservableObject {
static let shared = Config()
private init() {
reducedEffects = reducedEffectsStore
pasteboardDeduplicate = pasteboardDeduplicateStore
silentMode = silentModeStore
toastMode = toastModeStore
}
@UserDefaultsWrapper(key: "wiki.qaq.config.reducedEffects", defaultValue: false)
private var reducedEffectsStore
@Published var reducedEffects: Bool = false {
didSet { reducedEffectsStore = reducedEffects }
}
@UserDefaultsWrapper(key: "wiki.qaq.config.pasteboardDeduplicate", defaultValue: true)
private var pasteboardDeduplicateStore
@Published var pasteboardDeduplicate: Bool = true {
didSet { pasteboardDeduplicateStore = pasteboardDeduplicate }
}
@UserDefaultsWrapper(key: "wiki.qaq.config.silentMode", defaultValue: false)
private var silentModeStore
@Published var silentMode: Bool = true {
didSet { silentModeStore = silentMode }
}
@UserDefaultsWrapper(key: "wiki.qaq.config.toastMode", defaultValue: false)
private var toastModeStore
@Published var toastMode: Bool = true {
didSet { toastModeStore = toastMode }
}
}
================================================
FILE: App/Action/Action/Backend/Executor/Executor.swift
================================================
//
// Executor.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import AuxiliaryExecute
import Foundation
final class Executor {
static let shared = Executor()
let executorDir = ActionApp
.documentDirectory
.appendingPathComponent("Executor")
private init() {
let whoami = "/usr/bin/whoami"
let receipt = AuxiliaryExecute.spawn(command: whoami)
let username = receipt.stdout.trimmingCharacters(in: .whitespacesAndNewlines)
guard receipt.exitCode == 0, !username.isEmpty /* , username != "root" */ else {
fatalError("Malformed application permission")
}
print("[*] whoami \(username)")
do {
let findEnv = AuxiliaryExecute.spawn(
command: "/bin/zsh",
args: ["-c", "source ~/.zshrc 1>/dev/null 2>/dev/null && echo $PATH"]
)
let env = findEnv.stdout.trimmingCharacters(in: .whitespacesAndNewlines)
print("[*] setting up env PATH value \(findEnv.stdout)")
let envPathBuilder = env.components(separatedBy: ":")
.filter { FileManager.default.fileExists(atPath: $0) }
let origPathBuilder = (
ProcessInfo
.processInfo
.environment["PATH"] ?? ""
)
.components(separatedBy: ":")
.filter { FileManager.default.fileExists(atPath: $0) }
let newPath = Array(Set(envPathBuilder + origPathBuilder))
.joined(separator: ":")
setenv("PATH", newPath, 1)
}
try? FileManager.default.createDirectory(at: executorDir, withIntermediateDirectories: true)
}
enum ExecutorError: Error {
case unknown
}
func obtainXcodeCommandLineToolLocation() -> URL? {
let receipt = AuxiliaryExecute.spawn(
command: "/usr/bin/xcode-select",
args: ["--print-path"]
)
let path = receipt
.stdout
.trimmingCharacters(in: .whitespacesAndNewlines)
guard path != "/",
path.hasPrefix("/"),
FileManager.default.fileExists(atPath: path)
else {
return nil
}
return URL(fileURLWithPath: path)
}
func unarchiveTar(at: URL, toDest: URL) throws {
let receipt = AuxiliaryExecute.spawn(
command: "/usr/bin/tar",
args: ["-xf", at.path, "--directory", toDest.path]
)
guard receipt.exitCode == 0 else {
throw ExecutorError.unknown
}
}
func speak(_ str: String) {
AuxiliaryExecute.spawn(
command: "/usr/bin/say",
args: [str]
)
}
}
================================================
FILE: App/Action/Action/Backend/PasteboardManager/PasteboardManager+Event.swift
================================================
//
// PasteboardManager+Event.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import Foundation
extension PasteboardManager {
struct PEvent: Codable, Equatable, Hashable {
let content: String
let app: AppInfo?
init(content: String, app: PasteboardManager.AppInfo?) {
self.content = content
self.app = app
}
}
struct AppInfo: Codable, Equatable, Hashable {
let name: String
let bundleIdentifier: String
init(name: String, bundleIdentifier: String) {
self.name = name
self.bundleIdentifier = bundleIdentifier
}
}
}
================================================
FILE: App/Action/Action/Backend/PasteboardManager/PasteboardManager.swift
================================================
//
// PasteboardManager.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import AppKit
final class PasteboardManager {
static let shared = PasteboardManager()
private init() {
print("[*] setting up Pasteboard Manager")
Thread(
target: self,
selector: #selector(startMonitorThread),
object: nil
)
.start()
}
let systemPasteboard = NSPasteboard.general
private var monitorThread: Thread?
private var monitorRunLoop: RunLoop?
private var accessQueue = DispatchQueue(label: "wiki.qaq.PasteboardManager.accessQueue")
private var executeQueue = DispatchQueue(label: "wiki.qaq.PasteboardManager.executeQueue")
private var previousPasteboardChangeCount: Int?
private var previousPasteboardEvent: PEvent?
var eventBlockaded: Bool = false
@objc private func startMonitorThread() {
monitorThread = Thread.current
monitorRunLoop = RunLoop.current
defer {
self.monitorThread = nil
self.monitorRunLoop = nil
}
let timer = Timer(timeInterval: 0.25, repeats: true) { _ in
self.accessQueue.async { self.checkPasteboard() }
}
RunLoop.current.add(timer, forMode: .common)
CFRunLoopRun()
}
func clearLastEvent() {
print("[*] clearing previous pasteboard event")
accessQueue.async {
self.previousPasteboardEvent = nil
}
}
func requestCheckPasteboard() {
accessQueue.async { self.checkPasteboard() }
}
private func checkPasteboard() {
guard systemPasteboard.changeCount != previousPasteboardChangeCount else {
return
}
let newChangeCount = systemPasteboard.changeCount
print("[*] NSPasteboard has changeCount \(newChangeCount) previous at \(previousPasteboardChangeCount ?? -1)")
previousPasteboardChangeCount = newChangeCount
guard let copied = systemPasteboard.string(forType: .string) else {
print("[?] system pasteboard does not returns as string > ignoring")
return
}
let app: AppInfo? = obtainRunningApplication()
let event = PEvent(content: copied, app: app)
print("[*] PasteboardEvent content len \(copied.count) from \(app?.name ?? "nil")")
var shouldDispatchEvent = false
if let previousEvent = previousPasteboardEvent,
previousEvent != event || !Config.shared.pasteboardDeduplicate
{
shouldDispatchEvent = true
} else {
print("[*] event content did not change, ignore dispatch")
}
previousPasteboardEvent = event
if shouldDispatchEvent { prepareWorkflow(forPasteboardEvent: event) }
}
private func obtainRunningApplication() -> AppInfo? {
if let axApp = obtainRunningApplicationUsingAXElement() {
return axApp
}
if let currentApplication = NSWorkspace.shared.menuBarOwningApplication,
let name = currentApplication.localizedName,
let bundleIdentifier = currentApplication.bundleIdentifier
{
return AppInfo(name: name, bundleIdentifier: bundleIdentifier)
}
if let currentApplication = NSWorkspace.shared.frontmostApplication,
let name = currentApplication.localizedName,
let bundleIdentifier = currentApplication.bundleIdentifier
{
return AppInfo(name: name, bundleIdentifier: bundleIdentifier)
}
return nil
}
private func obtainRunningApplicationUsingAXElement() -> AppInfo? {
let systemWideElement: AXUIElement = AXUIElementCreateSystemWide()
var focusedElement: AnyObject?
AXUIElementCopyAttributeValue(
systemWideElement,
kAXFocusedUIElementAttribute as CFString,
&focusedElement
)
guard let element = focusedElement else { return nil }
var pid: pid_t = 0
AXUIElementGetPid(element as! AXUIElement, &pid)
guard pid > 0 else { return nil }
let runningApp = NSRunningApplication(processIdentifier: pid)
if let name = runningApp?.localizedName,
let bundleIdentifier = runningApp?.bundleIdentifier
{
return AppInfo(name: name, bundleIdentifier: bundleIdentifier)
}
return nil
}
private func prepareWorkflow(forPasteboardEvent pasteboardEvent: PEvent) {
assert(!Thread.isMainThread)
guard !eventBlockaded else {
print("[*] this pasteboard has been blockaded due to other process exists")
return
}
PasteboardManager.shared.eventBlockaded = true
defer {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
PasteboardManager.shared.eventBlockaded = false
}
}
print("[*] calling workflow manager to resolve event")
print(" content length \(pasteboardEvent.content.count)")
print(" from \(pasteboardEvent.app?.bundleIdentifier ?? "unknown") (\(pasteboardEvent.app?.name ?? "nope"))")
ActionManager.shared.handle(pasteboardEvent: pasteboardEvent)
}
}
================================================
FILE: App/Action/Action/Backend/StatusBarManager/StatusBarManager.swift
================================================
//
// StatusBarManager.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import Foundation
final class StatusBarManager {
var hasWindowOpened: Bool = false
static let shared = StatusBarManager()
private init() {}
}
================================================
FILE: App/Action/Action/Extension/AES.swift
================================================
//
// AES.swift
// PTFoundation
//
// Created by Lakr Aream on 12/15/20.
//
import CommonCrypto
import Foundation
import KeychainAccess
private var bundleId: String {
guard let id = Bundle.main.bundleIdentifier,
!id.isEmpty
else {
fatalError("AES Engine requires bundle identifier to work")
}
return id
}
private let keychainServiceID = "wiki.qaq.ActionBee.kcAccess"
private let keychainMainKeyID = "wiki.qaq.ActionBee.keychainMainKeyID"
private let keychainLabel = "ActionBee Main Crypto Key"
private let keychainComment = "ActionBee requires this crypto key to access your encrypted data and sign sensitive information."
public struct AES {
private let key: Data
private let iv: Data
public static let shared: AES = {
#if DEBUG
var keyBuilder = ""
#if os(macOS)
let platformExpert = IOServiceGetMatchingService(
kIOMainPortDefault,
IOServiceMatching("IOPlatformExpertDevice")
)
guard platformExpert > 0 else {
fatalError()
}
guard let serialNumber = (
IORegistryEntryCreateCFProperty(
platformExpert,
kIOPlatformSerialNumberKey as CFString,
kCFAllocatorDefault,
0
)
.takeUnretainedValue() as? String
)
else {
fatalError()
}
IOObjectRelease(platformExpert)
keyBuilder = serialNumber
#else
keyBuilder = "0xdeadbeef & 0xbadf00d & 0xdeadbeef & 0xbadf00d & 0xdeadbeef & 0xbadf00d"
#endif
let key = keyBuilder + keyBuilder + keyBuilder
guard let aes = AES(key: key, iv: key) else {
fatalError("failed to initialize crypto engine")
}
return aes
#else
let keychain = Keychain(service: keychainServiceID)
var retry = 3
var key: String?
repeat {
defer { retry -= 1 }
do {
let main = try keychain.getString(keychainMainKeyID)
if let main = main, main.count > 2 {
key = main
break
} else {
try keychain.remove(keychainMainKeyID)
let new = UUID().uuidString
key = new
try keychain
.label(keychainLabel)
.comment(keychainComment)
.set(new, key: keychainMainKeyID)
break
}
} catch {
continue
}
} while retry > 0
guard let key = key else {
fatalError("failed to load crypto keys")
}
guard let aes = AES(key: key, iv: key) else {
fatalError("failed to initialize crypto engine")
}
return aes
#endif
}()
internal init?(key initKey: String, iv initIV: String) {
if initKey.count < kCCKeySizeAES128 || initIV.count < kCCBlockSizeAES128 {
return nil
}
var initKey = initKey
while initKey.count < 32 {
initKey += initKey
}
while initKey.count > 32 {
initKey.removeLast()
}
guard initKey.count == kCCKeySizeAES128 || initKey.count == kCCKeySizeAES256,
let keyData = initKey.data(using: .utf8)
else {
return nil
}
var initIV = initIV
while initIV.count < kCCBlockSizeAES128 {
initIV += initIV
}
while initIV.count > kCCBlockSizeAES128 {
initIV.removeLast()
}
guard initIV.count == kCCBlockSizeAES128, let ivData = initIV.data(using: .utf8) else {
return nil
}
key = keyData
iv = ivData
}
// MARK: - API
public func encrypt(data: Data) -> Data? {
crypt(data: data, option: CCOperation(kCCEncrypt))
}
public func decrypt(data: Data) -> Data? {
crypt(data: data, option: CCOperation(kCCDecrypt))
}
// MARK: - INTERNAL
private func crypt(data: Data?, option: CCOperation) -> Data? {
guard let data = data else { return nil }
let cryptLength = data.count + kCCBlockSizeAES128
var cryptData = Data(count: cryptLength)
let keyLength = key.count
let options = CCOptions(kCCOptionPKCS7Padding)
var bytesLength = Int(0)
let status = cryptData.withUnsafeMutableBytes { cryptBytes in
data.withUnsafeBytes { dataBytes in
iv.withUnsafeBytes { ivBytes in
key.withUnsafeBytes { keyBytes in
CCCrypt(option, CCAlgorithm(kCCAlgorithmAES), options, keyBytes.baseAddress, keyLength, ivBytes.baseAddress, dataBytes.baseAddress, data.count, cryptBytes.baseAddress, cryptLength, &bytesLength)
}
}
}
}
guard UInt32(status) == UInt32(kCCSuccess) else {
assertionFailure()
return nil
}
cryptData.removeSubrange(bytesLength ..< cryptData.count)
return cryptData
}
}
================================================
FILE: App/Action/Action/Extension/Data.swift
================================================
//
// Data.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import CommonCrypto
import Foundation
extension Data {
func sha256() -> String {
var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
withUnsafeBytes {
_ = CC_SHA256($0.baseAddress, CC_LONG(count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
let sha256Hex = hexBytes.joined()
return sha256Hex
}
}
================================================
FILE: App/Action/Action/Extension/DispatchQueue.swift
================================================
//
// DispatchQueue.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import Foundation
extension DispatchQueue {
static func withMainAndWait(block: @escaping () -> Void) {
assert(!Thread.isMainThread)
guard !Thread.isMainThread else {
block()
return
}
let sem = DispatchSemaphore(value: 0)
DispatchQueue.main.async {
block()
sem.signal()
}
sem.wait()
}
}
================================================
FILE: App/Action/Action/Extension/Notification.swift
================================================
//
// Notification.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import Foundation
extension Notification.Name {
static let editAction = Notification.Name("wiki.qaq.editAction")
}
================================================
FILE: App/Action/Action/Extension/Result.swift
================================================
//
// Result.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import Foundation
public extension Result where Success == Void {
static var success: Result { .success(()) }
}
================================================
FILE: App/Action/Action/Extension/Throttle.swift
================================================
// SwiftThrottle.swift
// Twitter @Lakr233
//
// Created by Lakr Aream on 12/12/20.
//
import Foundation
/*
This throttle is intended to prevent the program from crashing with
too many requests or is used for saving computer resources.
** Swift Throttle is not designed for operations that require high time accuracy **
*/
// MARK: - THROTTLE
public class Throttle {
// MARK: - PROPERTY
/// Setup with these values to control the throttle behave
/// - minimumDelay >= 0.5 second is suggested
public private(set) var minimumDelay: TimeInterval
public private(set) var workingQueue: DispatchQueue
/// lock when dispatch job to execution
private var executeLock = NSLock()
/// These value controls throttle behavior
public private(set) var lastExecute: Date?
public private(set) var lastRequestWasCanceled: Bool = false
public private(set) var scheduled: Bool = false
/// Lock when setting jobs, required by thread safe design
private var _assignmentLock = NSLock()
private var _assignment: (() -> Void)?
public private(set) var assignment: (() -> Void)? {
set {
_assignmentLock.lock()
defer { _assignmentLock.unlock() }
_assignment = newValue
}
get {
_assignmentLock.lock()
defer { _assignmentLock.unlock() }
return _assignment
}
}
// MARK: - INIT
/// Create a throttle
/// - Parameters:
/// - minimumDelay: in second
/// - queue: the queue that job will executed on, default to main
public init(minimumDelay delay: TimeInterval,
queue: DispatchQueue = DispatchQueue.main)
{
minimumDelay = delay
workingQueue = queue
#if DEBUG
if minimumDelay < 0.5 {
// we suggest minimumDelay to be at least 0.5 second
debugPrint("[SwiftThrottle] "
+ "minimumDelay(\(minimumDelay) less then 0.5s will be inaccurate"
+ ", last callback not guaranteed")
}
#endif
}
// MARK: - API
/// Update property minimumDelay
/// - Parameter interval: in second
public func updateMinimumDelay(interval: Double) {
executeLock.lock()
minimumDelay = interval
executeLock.unlock()
}
/// Assign job to throttle
/// - Parameter job: call block
public func throttle(job: (() -> Void)?) {
realThrottle(job: job, useAssignment: false)
}
// MARK: - BACKEND
/// Check nothing but execute
/// - Parameter capturedJob: block to execute
private func releaseExec(capturedJob: @escaping (() -> Void)) {
lastExecute = Date()
workingQueue.async {
capturedJob()
}
}
/// Throttle is working here
/// - Parameters:
/// - job: block that was required to execute
/// - useAssignment: shall we overwrite assigned job?
private func realThrottle(job: (() -> Void)?, useAssignment: Bool) {
// lock down every thing when resigning job
executeLock.lock()
defer { self.executeLock.unlock() }
// if called from rescheduled job, cancel job overwrite
var capturedJobDecision: (() -> Void)?
if !useAssignment {
// resign job every time calling from user
assignment = job
capturedJobDecision = job
} else {
capturedJobDecision = assignment
}
guard let capturedJob = capturedJobDecision else { return }
// MARK: LOCK BEGIN
if let lastExec = lastExecute {
// executed before, value negative
let timeBetween = -lastExec.timeIntervalSinceNow
if timeBetween < minimumDelay {
// The throttle will be reprogrammed once for future execution
lastRequestWasCanceled = true
if !scheduled {
scheduled = true
let dispatchTime = Double(minimumDelay - timeBetween + 0.01)
// Preventing trigger failures
// This is where the inaccuracy comes from
workingQueue.asyncAfter(deadline: .now() + dispatchTime) {
self.realThrottle(job: nil, useAssignment: true)
self.scheduled = false
}
}
} else {
// Throttle release to execution
releaseExec(capturedJob: capturedJob)
}
}
else // never called before, release to execution
{
releaseExec(capturedJob: capturedJob)
}
// MARK: LOCK END
}
}
================================================
FILE: App/Action/Action/Extension/UserDefault.swift
================================================
//
// UserDefault.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import Foundation
#if DEBUG
private let keyPrefix = "debug."
#else
private let keyPrefix = ""
#endif
@propertyWrapper
struct UserDefaultsWrapper {
let key: String
let defaultValue: Value
var storage: UserDefaults = .standard
init(key: String, defaultValue: Value, storage: UserDefaults = .standard) {
self.key = keyPrefix + key
self.defaultValue = defaultValue
self.storage = storage
}
var wrappedValue: Value {
get {
let value = storage.value(forKey: key) as? Value
return value ?? defaultValue
}
set {
storage.setValue(newValue, forKey: key)
}
}
}
extension UserDefaultsWrapper where Value: ExpressibleByNilLiteral {
init(key: String, storage: UserDefaults = .standard) {
self.init(key: key, defaultValue: nil, storage: storage)
}
}
private let documentEncoder = PropertyListEncoder()
private let documentDecoder = PropertyListDecoder()
@propertyWrapper
struct CodableDefaultsWrapper {
let key: String
let defaultValue: Value
var storage: UserDefaults = .standard
init(key: String, defaultValue: Value, storage: UserDefaults = .standard) {
self.key = keyPrefix + key
self.defaultValue = defaultValue
self.storage = storage
}
var wrappedValue: Value {
get {
guard let data = storage.value(forKey: key) as? Data,
let value = try? documentDecoder.decode(Value.self, from: data)
else {
return defaultValue
}
return value
}
set {
guard let data = try? documentEncoder.encode(newValue) else {
return
}
storage.setValue(data, forKey: key)
}
}
}
@propertyWrapper
struct EncryptedCodableDefaultsWrapper {
let key: String
let defaultValue: Value
var storage: UserDefaults = .standard
init(key: String, defaultValue: Value, storage: UserDefaults = .standard) {
self.key = keyPrefix + key
self.defaultValue = defaultValue
self.storage = storage
}
var wrappedValue: Value {
get {
guard let data = storage.value(forKey: key) as? Data,
let decrypted = AES.shared.decrypt(data: data),
let value = try? documentDecoder.decode(Value.self, from: decrypted)
else {
return defaultValue
}
return value
}
set {
guard let data = try? documentEncoder.encode(newValue),
let encrypt = AES.shared.encrypt(data: data)
else {
return
}
storage.setValue(encrypt, forKey: key)
}
}
}
extension EncryptedCodableDefaultsWrapper where Value: ExpressibleByNilLiteral {
init(key: String, storage: UserDefaults = .standard) {
self.init(key: key, defaultValue: nil, storage: storage)
}
}
================================================
FILE: App/Action/Action/Extension/View.swift
================================================
//
// View.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import SwiftUI
extension View {
func usePreferredContentSize() -> some View {
frame(
minWidth: 400, idealWidth: 500, maxWidth: .infinity,
minHeight: 300, idealHeight: 350, maxHeight: .infinity,
alignment: .center
)
}
}
================================================
FILE: App/Action/Action/Interface/ActionModule/ModuleCreateView.swift
================================================
//
// ModuleCreateView.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import SwiftUI
struct ModuleCreateSheet: View {
@Environment(\.presentationMode) var presentationMode
@State var moduleName: String = "Module - 0x\(Int.random(in: 100_000 ... 999_999))"
@State var selectedTemplate: ActionManager.ModuleTemplateIdentifier = .swift
@State var showProgress: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 6) {
if showProgress {
ProgressView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
Label("Create Action", systemImage: "doc.badge.gearshape.fill")
.font(.system(.headline, design: .rounded))
Divider()
TextField("Module Name", text: $moduleName)
Picker("Language", selection: $selectedTemplate) {
ForEach(ActionManager.ModuleTemplateIdentifier.allCases, id: \.self) { template in
Text(template.obtainTemplateDetails().getLanguage())
}
}
Divider()
HStack {
Button("Cancel") {
presentationMode.wrappedValue.dismiss()
}
.keyboardShortcut(.cancelAction)
Spacer()
Button("Next") {
callCreate()
}
.buttonStyle(.borderedProminent)
.keyboardShortcut(.defaultAction)
}
}
}
.padding()
.frame(width: 300, alignment: .center)
}
func callCreate() {
showProgress = true
DispatchQueue.global().async {
var actionId: UUID?
defer {
DispatchQueue.main.async {
presentationMode.wrappedValue.dismiss()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
if let id = actionId {
ActionManager.shared.initialingAciton.insert(id)
NotificationCenter.default.post(name: .editAction, object: id)
}
}
}
print("[*] \(moduleName) \(selectedTemplate)")
actionId = ActionManager.shared.createAction(
withName: moduleName,
withModuleTemplate: selectedTemplate
)
}
}
}
================================================
FILE: App/Action/Action/Interface/ActionModule/ModuleEditView.swift
================================================
//
// ModuleEditView.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import SwiftUI
import SymbolPicker
struct ModuleEditView: View {
let id: UUID
@Environment(\.presentationMode) var presentationMode
@State var editingAction: ActionManager.Action? = nil
@State var actionEnabled: Bool = true
@State var openSymbolPicker: Bool = false
@State var openCompileView: Bool = false
@State var hoverApplication: String? = nil
@State var compileLog: String = ""
@State var compilerFinished: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 8) {
if editingAction == nil {
brokenModule
} else {
HStack {
Label("Edit Action", systemImage: "slider.horizontal.3")
.font(.system(.headline, design: .rounded))
Spacer()
Button {
delete()
} label: {
Image(systemName: "trash")
.font(.system(.headline, design: .rounded))
.foregroundColor(.accentColor)
}
.buttonStyle(.plain)
}
Divider()
basicMetaBlock
enableForAppsBlock
editCodeBlock
Divider()
HStack {
Button("Cancel") {
presentationMode.wrappedValue.dismiss()
}
.keyboardShortcut(.cancelAction)
Spacer()
Button("Save") {
finalizeEdit()
}
.buttonStyle(.borderedProminent)
.keyboardShortcut(.defaultAction)
}
}
}
.onAppear {
editingAction = ActionManager.shared[id]
actionEnabled = ActionManager.shared.enabledActions.contains(id)
}
.opacity(openCompileView ? 0 : 1)
.overlay(compileOverlay)
.padding()
.frame(width: 500, alignment: .center)
}
var compileOverlay: some View {
VStack(alignment: .leading) {
if !compilerFinished { ProgressView().padding(.top, 20) }
Spacer().frame(height: 20)
Text(compilerFinished ? "Compile Finished" : "Compiling Source")
.font(.headline)
Spacer().frame(height: 6)
if !compilerFinished { RandomCodeTextView() }
Divider()
ScrollView(.vertical, showsIndicators: true) {
VStack(alignment: .leading, spacing: 4) {
ForEach(Array(
compileLog
.components(separatedBy: "\n")
.reversed()
.enumerated()
), id: \.offset) { _, log in
Text(log).textSelection(.enabled)
}
.font(.system(.footnote, design: .monospaced))
.opacity(0.5)
}
}
Button("Cancel") {
compileLog = ""
openCompileView = false
}
.opacity(compilerFinished ? 1 : 0)
}
.opacity(openCompileView ? 1 : 0)
}
var brokenModule: some View {
VStack {
Image(systemName: "xmark.seal.fill")
.font(.system(size: 36, weight: .semibold, design: .rounded))
.foregroundColor(.pink)
.frame(width: 80, height: 80)
Text("Broken Module")
.font(.headline)
Divider()
HStack {
Button("Delete") {
ActionManager.shared.deleteModule(withId: id)
}
Button("Close") {
presentationMode.wrappedValue.dismiss()
}
.buttonStyle(.borderedProminent)
}
}
.padding()
}
var actionIcon: String {
guard let icon = editingAction?.icon,
!icon.isEmpty
else {
return "text.append"
}
return icon
}
var basicMetaBlock: some View {
Group {
Toggle("Enabled", isOn: $actionEnabled)
.font(.system(.headline, design: .rounded))
HStack {
Button {
openSymbolPicker = true
} label: {
Image(systemName: actionIcon)
}
TextField("Name", text: Binding(
get: {
editingAction?.name ?? ""
},
set: { newValue in
editingAction?.name = newValue
}
))
Text("Timeout: ")
TextField("Name", text: Binding(
get: {
String(editingAction?.timeout ?? 5)
},
set: { newValue in
editingAction?.timeout = Int(newValue) ?? 5
}
))
.frame(width: 26)
Text("s")
}
Text("ID: \(editingAction?.id.uuidString ?? "0x4422DEADBEEF")")
.textSelection(.enabled)
.font(.system(.footnote, design: .monospaced))
}
.sheet(isPresented: $openSymbolPicker) {
SymbolPicker(symbol: Binding(
get: {
actionIcon
},
set: { newValue in
editingAction?.icon = newValue
}
))
}
}
var enableForAppsBlock: some View {
Group {
HStack {
Text("Enable In App")
.font(.system(.headline, design: .rounded))
Spacer()
Button {
addApp()
} label: {
Image(systemName: "plus")
.foregroundColor(.accentColor)
.font(.system(.headline, design: .rounded))
}
.buttonStyle(.plain)
}
if let appList = editingAction?.enabledAppList,
!appList.isEmpty
{
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(appList, id: \.self) { appId in
ApplicationView(appId: appId)
.blur(radius: hoverApplication == appId ? 6 : 0)
.overlay {
Button {
editingAction?.enabledAppList = editingAction?
.enabledAppList
.filter { $0 != appId }
?? []
} label: {
Image(systemName: "xmark")
.foregroundColor(.white)
.font(.system(.headline, design: .rounded))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.black.opacity(0.5))
.cornerRadius(4)
}
.buttonStyle(.plain)
.opacity(hoverApplication == appId ? 1 : 0)
}
.animation(.interactiveSpring(), value: hoverApplication)
.onHover { hover in
if hover {
hoverApplication = appId
} else {
hoverApplication = nil
}
}
}
}
}
.frame(height: 26)
} else {
Button {
addApp()
} label: {
Label("Enabled for All Apps", systemImage: "app.badge.checkmark")
.font(.system(.subheadline, design: .rounded))
.frame(height: 26)
.frame(maxWidth: .infinity)
.background(Color.accentColor.opacity(0.1))
.cornerRadius(4)
}
.buttonStyle(.plain)
}
Text("This pasteboard action will only run if copying from these apps")
.textSelection(.enabled)
.font(.system(.footnote))
}
}
var editCodeBlock: some View {
Group {
Text("Coding")
.font(.system(.headline, design: .rounded))
HStack(spacing: 8) {
Button("Edit Code") {
editModule()
}
.buttonStyle(.borderedProminent)
Button("Show in Finder") {
showInFinder()
}
Button("Export") {
exportModule()
}
}
VStack(alignment: .leading, spacing: 2) {
Text("Module Template: \(editingAction?.template.obtainTemplateDetails().getLanguage() ?? "Unknown")")
Text(editingAction?.template.obtainTemplateDetails().getBuildHint() ?? "No Build Hint")
.underline()
Text("You should recompile, click save, this module each time you edit it")
}
.textSelection(.enabled)
.font(.system(.footnote))
}
}
func finalizeEdit() {
guard ActionManager.shared[id] != nil else {
presentationMode.wrappedValue.dismiss()
return
}
guard let action = editingAction else {
presentationMode.wrappedValue.dismiss()
return
}
ActionManager.shared.invalidateArtifactCache(forAction: id)
ActionManager.shared.enabledActions = ActionManager.shared
.enabledActions
.filter { $0 != id }
guard actionEnabled else {
presentationMode.wrappedValue.dismiss()
return
}
ActionManager.shared.enabledActions += [id]
ActionManager.shared.initialingAciton.remove(id)
compile { result in
switch result {
case .success:
ActionManager.shared[id] = action
presentationMode.wrappedValue.dismiss()
case let .failure(failure):
compilerFinished = true
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = "Unable to compile this action: \(failure.message)"
if let window = NSApp.keyWindow {
alert.beginSheetModal(for: window)
} else {
alert.runModal()
}
}
}
}
func delete() {
let alert = NSAlert()
alert.messageText = NSLocalizedString("Are you sure you want to delete this module? This operation can not be undone.", comment: "")
alert.alertStyle = .critical
alert.addButton(withTitle: NSLocalizedString("Delete", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
guard let window = NSApp.keyWindow else {
return
}
alert.beginSheetModal(for: window) { resp in
guard resp == .alertFirstButtonReturn else {
return
}
presentationMode.wrappedValue.dismiss()
DispatchQueue.main.async {
ActionManager.shared[id] = nil
}
}
}
func addApp() {
let openPanel = NSOpenPanel()
openPanel.prompt = NSLocalizedString("Select Application", comment: "")
openPanel.allowedContentTypes = [.application]
openPanel.allowsMultipleSelection = true
openPanel.canChooseDirectories = true
openPanel.treatsFilePackagesAsDirectories = true
openPanel.directoryURL = URL(fileURLWithPath: "/Applications/")
guard let window = NSApp.keyWindow else {
return
}
openPanel.beginSheetModal(for: window) { resp in
guard resp == .OK else {
return
}
var buildId: Set = []
for id in editingAction?.enabledAppList ?? [] {
buildId.insert(id)
}
for url in openPanel.urls {
guard let bundle = Bundle(path: url.path),
let id = bundle.bundleIdentifier
else {
continue
}
buildId.insert(id)
}
editingAction?.enabledAppList = Array(buildId).sorted()
}
}
func showInFinder() {
let url = ActionManager
.shared
.actionModuleBaseUrl
.appendingPathComponent(editingAction?.id.uuidString ?? "")
guard NSWorkspace.shared.open(url) else {
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = NSLocalizedString("Failed to load this module", comment: "")
if let window = NSApp.keyWindow {
alert.beginSheetModal(for: window)
}
return
}
}
func editModule() {
let result = editingAction?.template.obtainTemplateDetails()
.openDesignatedEditor(id: id)
if case let .failure(failure) = result {
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = failure.message
if let window = NSApp.keyWindow {
alert.beginSheetModal(for: window)
}
}
}
func exportModule() {
let panel = NSSavePanel()
panel.nameFieldStringValue = "Module Export - \(editingAction?.name ?? "Unnamed")"
guard let window = NSApp.keyWindow else {
return
}
panel.beginSheetModal(for: window) { resp in
guard resp == .OK,
let url = panel.url
else {
return
}
ActionManager.shared.updateActionModuleManifest(onActionId: id)
try? FileManager.default.removeItem(at: url)
try? FileManager.default.copyItem(
at: ActionManager.shared.actionModuleBaseUrl.appendingPathComponent(id.uuidString),
to: url
)
}
}
func compile(completion: @escaping (Result) -> Void = { _ in }) {
openCompileView = true
guard let action = editingAction else {
openCompileView = false
completion(.failure(.brokenResources))
return
}
DispatchQueue.global().async {
let result = ActionManager.shared.issueCompile(forAction: action.id) { str in
DispatchQueue.withMainAndWait {
compileLog.append(str)
}
}
DispatchQueue.main.async {
completion(result)
}
}
}
}
================================================
FILE: App/Action/Action/Interface/ActionModule/ModuleElementView.swift
================================================
//
// ModuleElementView.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import SwiftUI
struct ModuleElementView: View {
let id: UUID
let notificationPublisher = NotificationCenter
.default
.publisher(for: .editAction)
.receive(on: RunLoop.main)
@StateObject var actionManager = ActionManager.shared
@State var openEdit: Bool = false
var gradientColor: Gradient {
if actionManager.enabledActions.contains(id) {
if actionManager.artifacts[id] == nil {
return Gradient(colors: [.pink, .red])
} else {
return Gradient(colors: [.yellow, .orange])
}
} else {
return Gradient(colors: [.gray, .black.opacity(0.8)])
}
}
var body: some View {
Button {
openEdit = true
} label: {
LinearGradient(
gradient: gradientColor,
startPoint: .topTrailing,
endPoint: .bottomTrailing
)
.overlay { Color.orange.opacity(0.5) }
.overlay { content }
.cornerRadius(8)
.clipped()
.frame(width: 140, height: 80)
}
.overlay {
if actionManager.artifacts[id] == nil {
Image(systemName: "xmark.octagon.fill")
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
.padding(4)
}
}
.buttonStyle(.plain)
.onHover { hover in
if hover {
NSCursor.pointingHand.push()
} else {
NSCursor.pop()
}
}
.onReceive(notificationPublisher) { notification in
guard let notificationId = notification.object as? UUID,
notificationId == id
else {
return
}
openEdit = true
}
.sheet(isPresented: $openEdit) {
ModuleEditView(id: id)
}
}
var content: some View {
Group {
if let action = actionManager[id] {
VStack(spacing: 4) {
Image(systemName: action.icon)
.font(.system(.headline, design: .rounded))
.foregroundColor(.white)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
Text(action.name)
.font(.system(.headline, design: .rounded))
.lineLimit(3)
.foregroundColor(.white)
.frame(maxWidth: .infinity, alignment: .leading)
}
.background(
Image(systemName: action.icon)
.font(.system(size: 48, weight: .semibold, design: .rounded))
.foregroundColor(.white)
.opacity(0.1)
.offset(x: 50, y: 10)
)
.padding(8)
} else {
Text("Error").font(.headline)
}
}
}
}
================================================
FILE: App/Action/Action/Interface/ActionModule/ModuleImportView.swift
================================================
//
// ModuleImportView.swift
// Action
//
// Created by Lakr Aream on 2022/8/18.
//
import SwiftUI
struct ModuleImportView: View {
let url: URL
@Environment(\.presentationMode) var presentationMode
@State var openEdit: Bool = false
@State var editingAction: ActionManager.Action.ID? = nil
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 42, weight: .semibold, design: .rounded))
.foregroundColor(.pink)
Text("You are about to import an untrusted module")
.font(.system(.headline))
.foregroundColor(.pink)
Text("Importing malicious module may damage your system, you are in charge to review this module.")
.font(.system(.footnote))
.foregroundColor(.pink)
HStack {
Button("Trust & Import") {
startImport()
}
.keyboardShortcut(.defaultAction)
.tint(.pink)
.buttonStyle(.borderedProminent)
Button("Cancel") {
presentationMode.wrappedValue.dismiss()
}
.keyboardShortcut(.cancelAction)
}
Divider()
Text(url.path)
.underline()
.font(.system(.footnote, design: .monospaced))
.opacity(0.5)
.onHover { if $0 { NSCursor.pointingHand.push() } else { NSCursor.pop() }}
.onTapGesture { NSWorkspace.shared.open(url) }
}
.padding()
.sheet(isPresented: $openEdit) {
ModuleEditView(id: editingAction ?? .init())
}
.onChange(of: openEdit) { newValue in
if newValue == false, editingAction != nil {
presentationMode.wrappedValue.dismiss()
}
}
.frame(width: 400)
}
func startImport() {
DispatchQueue.global().async {
let result = ActionManager.shared.importModule(at: url)
DispatchQueue.main.async {
switch result {
case let .success(action):
openEdit = true
editingAction = action
case let .failure(failure):
guard let window = NSApp.keyWindow else {
presentationMode.wrappedValue.dismiss()
return
}
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = failure.localizedDescription
alert.addButton(withTitle: "OK")
alert.beginSheetModal(for: window) { _ in
presentationMode.wrappedValue.dismiss()
}
}
}
}
}
}
================================================
FILE: App/Action/Action/Interface/ActionModule/ModuleManageView.swift
================================================
//
// ModuleManageView.swift
// Action
//
// Created by Lakr Aream on 2022/7/26.
//
import SwiftUI
struct ModuleManageView: View {
@ObservedObject var actionManager = ActionManager.shared
@State var searchKey: String = ""
@State var openCreate: Bool = false
@State var importQueue: [URL]? = nil
@State var importingItem: URL? = nil
var actions: [ActionManager.Action] {
if searchKey.isEmpty {
return actionManager.actions
} else {
let key = searchKey.lowercased()
return actionManager
.actions
.filter { $0.name.lowercased().contains(key) }
}
}
var body: some View {
GeometryReader { r in
if actionManager.actions.isEmpty {
VStack(spacing: 12) {
Image(systemName: "arrow.up")
.font(.system(size: 26, weight: .regular, design: .rounded))
Text("Create an action by click plus button on toolbar to process your pasteboard event. Format text, clean up links, speak when copy from special app, send to your device, etc etc. Choose an language you are familiar with to get start.")
.font(.system(.subheadline))
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 140, maximum: 140))], alignment: .leading, spacing: 8) {
ForEach(actions, id: \.hashValue) { action in
ModuleElementView(id: action.id)
}
}
.padding(10)
.animation(.interactiveSpring(), value: r.size)
.animation(.interactiveSpring(), value: searchKey)
}
}
}
.sheet(isPresented: $openCreate) { ModuleCreateSheet() }
.sheet(
isPresented: Binding(
get: { importingItem != nil },
set: { opened in
importingItem = nil
if !opened {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if !(importQueue?.isEmpty ?? true) {
importQueue?.removeFirst()
}
checkImportQueue()
}
}
}
)
) {
ModuleImportView(url: importingItem ?? URL(fileURLWithPath: "/bad/"))
}
.searchable(text: $searchKey)
.toolbar {
ToolbarItem {
Button {
openCreate = true
} label: {
Label("Add Action", systemImage: "plus")
}
.keyboardShortcut("n", modifiers: .command)
}
ToolbarItem {
Button {
importActions()
} label: {
Label("Import Action", systemImage: "square.and.arrow.down")
}
}
}
.navigationTitle("Module")
.usePreferredContentSize()
}
func checkImportQueue() {
guard let newValue = importQueue else {
return
}
guard !newValue.isEmpty else {
importQueue = nil
importingItem = nil
return
}
importingItem = newValue.first
}
func importActions() {
let panel = NSOpenPanel()
panel.canChooseDirectories = true
panel.canChooseFiles = false
panel.resolvesAliases = true
panel.treatsFilePackagesAsDirectories = true
panel.allowsMultipleSelection = true
guard let window = NSApp.keyWindow else {
return
}
panel.beginSheetModal(for: window) { resp in
guard resp == .OK,
!panel.urls.isEmpty
else {
return
}
self.importQueue = panel.urls
self.checkImportQueue()
}
}
func importModule(at: URL) {
assert(!Thread.isMainThread)
let sem = DispatchSemaphore(value: 0)
DispatchQueue.main.async {
guard let window = NSApp.keyWindow else {
sem.signal()
return
}
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = "You are about to import an Action Module which is untrusted with no signature. Importing malicious modules can pose unknown risks and there is no sandbox nor container dealing with it."
alert.informativeText = at.path
alert.addButton(withTitle: "Trust And Import")
alert.addButton(withTitle: "Cancel")
alert.beginSheetModal(for: window) { resp in
guard resp == .alertFirstButtonReturn else {
sem.signal()
return
}
DispatchQueue.global().async {
let result = actionManager.importModule(at: at)
if case let .failure(failure) = result {
print(failure.localizedDescription)
let sem2 = DispatchSemaphore(value: 0)
DispatchQueue.main.async {
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = "Failed to import this module"
alert.informativeText = failure.localizedDescription
alert.beginSheetModal(for: window) { _ in sem2.signal() }
}
sem2.wait()
}
sem.signal()
}
}
}
sem.wait()
}
}
================================================
FILE: App/Action/Action/Interface/Effect/RandomCodeTextView.swift
================================================
//
// RandomCodeTextView.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import SwiftUI
struct RandomCodeTextView: View {
@State var code = "Made with love by @Lakr233 "
let timer = Timer
.publish(every: 0.1, on: .main, in: .common)
.autoconnect()
var body: some View {
Text(code)
.font(.system(.footnote, design: .monospaced))
.lineLimit(1)
.onReceive(timer) { _ in
if code.count > 50 { code = "" }
for _ in 0 ... Int.random(in: 1 ... 3) {
if let c = "`1234567890-=qwertyuiop[]asdfghjkl;'\\zxcvbnm,./".randomElement() {
code += String(c)
}
}
}
}
}
================================================
FILE: App/Action/Action/Interface/Generic/ApplicationView.swift
================================================
//
// ApplicationView.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import SwiftUI
struct ApplicationView: View {
let appId: String
var body: some View {
Group {
if let url = NSWorkspace
.shared
.urlForApplication(withBundleIdentifier: appId),
let bundle = Bundle(url: url)
{
HStack(spacing: 4) {
Image(nsImage: NSWorkspace.shared.icon(forFile: url.path))
.resizable()
.antialiased(true)
.frame(width: 24, height: 24)
.cornerRadius(4)
.clipped()
VStack(alignment: .leading, spacing: 2) {
Text(bundle.infoDictionary?[kCFBundleNameKey as String] as? String ?? "Unknown Name")
.font(.system(size: 10, weight: .semibold, design: .rounded))
.lineLimit(1)
Text(appId)
.font(.system(size: 6, weight: .semibold, design: .monospaced))
.lineLimit(1)
}
}
} else {
HStack(spacing: 4) {
Image(systemName: "questionmark.app.dashed")
.font(.system(size: 16, weight: .regular, design: .rounded))
Text(appId)
.font(.system(size: 10, weight: .semibold, design: .rounded))
}
}
}
.frame(height: 26)
}
}
================================================
FILE: App/Action/Action/Interface/Generic/DiagnosticLogView.swift
================================================
//
// DiagnosticLogView.swift
// Action
//
// Created by Lakr Aream on 2022/8/15.
//
import SwiftUI
class Logger: ObservableObject {
fileprivate static let shared = Logger()
private let logCountLimitation = 4096
private init() {
logs.reserveCapacity(logCountLimitation + 1)
}
struct Log: Identifiable, Equatable {
var id: UUID = .init()
var message: String
}
@Published var logs: [Log] = []
private var logsLock = NSLock()
fileprivate func append(_ str: String) {
DispatchQueue.global().async { [self] in
logsLock.lock()
var read = logs
read.append(.init(message: str))
if read.count > logCountLimitation {
read.removeFirst(read.count - logCountLimitation)
}
DispatchQueue.withMainAndWait {
self.logs = read
}
logsLock.unlock()
}
}
}
// overwrite print function
func print(_ str: String) {
let str = str.trimmingCharacters(in: .newlines)
Swift.print(str)
Logger.shared.append(str)
}
struct DiagnosticLogView: View {
@StateObject var logger = Logger.shared
@State var highlight: Logger.Log.ID?
@State var searchKey: String = ""
var logs: [Logger.Log] {
if searchKey.count > 0 {
let key = searchKey.lowercased()
return logger
.logs
.filter { $0.message.lowercased().contains(key) }
} else {
return logger.logs
}
}
var body: some View {
ScrollView(.vertical, showsIndicators: true) {
ScrollViewReader { reader in
LazyVStack(alignment: .leading, spacing: 0) {
ForEach(logs) { log in
ScrollView(.horizontal, showsIndicators: false) {
Text(log.message)
.textSelection(.enabled)
}
.frame(maxWidth: .infinity)
.padding(2)
.background(
RoundedRectangle(cornerRadius: 4)
.foregroundColor(.accentColor)
.opacity(highlight == log.id ? 0.1 : 0)
.animation(.interactiveSpring(), value: highlight)
)
.tag(log.id)
.onHover { hover in
if hover {
highlight = log.id
} else {
highlight = nil
}
}
}
.font(.system(size: 10, weight: .regular, design: .monospaced))
}
.padding(10)
.onChange(of: logger.logs) { newValue in
guard let id = newValue.last?.id else {
return
}
withAnimation(.interactiveSpring()) {
reader.scrollTo(id)
}
}
}
}
.searchable(text: $searchKey)
.toolbar {
ToolbarItem {
Button {
let panel = NSSavePanel()
panel.nameFieldStringValue = "ActionBee Diagnostic \(Int(Date().timeIntervalSince1970)).log"
guard let window = NSApp.keyWindow else {
return
}
panel.beginSheetModal(for: window) { resp in
guard resp == .OK, let url = panel.url else {
return
}
let logs = logger.logs.map(\.message).joined(separator: "\n")
try? logs.write(toFile: url.path, atomically: true, encoding: .utf8)
}
} label: {
Label("Share", systemImage: "square.and.arrow.up")
}
}
}
.navigationTitle("Diagnostic")
.usePreferredContentSize()
}
}
================================================
FILE: App/Action/Action/Interface/Generic/HistoryView.swift
================================================
//
// HistoryView.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import SwiftUI
struct HistoryView: View {
@StateObject var actionManager = ActionManager.shared
@State var searchKey = ""
@State var hoverId: ActionManager.HistoryElement.ID? = nil
var histories: [ActionManager.HistoryElement] {
if searchKey.isEmpty {
return actionManager.histories
}
let key = searchKey.lowercased()
return actionManager
.histories
.filter { $0.search(with: key) }
}
var body: some View {
Group {
if histories.isEmpty {
VStack(spacing: 12) {
Image(systemName: "rectangle.dashed.badge.record")
.font(.system(size: 26, weight: .regular, design: .rounded))
Text("No History Was Found")
.font(.system(.footnote))
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
ScrollView {
LazyVStack(spacing: 2) {
ForEach(histories.reversed()) { record in
HStack(alignment: .top, spacing: 6) {
Text("> ")
.font(.system(.subheadline, design: .rounded))
Divider()
HistoryRecordView(record: record)
}
.frame(maxWidth: .infinity)
.padding(2)
.background(Color.accentColor.opacity(record.id == hoverId ? 0.1 : 0))
.cornerRadius(8)
.onHover { hover in
hoverId = hover ? record.id : nil
}
}
}
.padding(10)
}
.animation(.interactiveSpring(), value: hoverId)
.animation(.interactiveSpring(), value: searchKey)
}
}
.toolbar {
ToolbarItem {
Button { clearHistory() } label: {
Label("Clear History", systemImage: "xmark.circle")
}
}
}
.searchable(text: $searchKey)
.navigationTitle("History")
.usePreferredContentSize()
}
func clearHistory() {
let alert = NSAlert()
alert.alertStyle = .critical
alert.messageText = NSLocalizedString("Are you sure you want to delete all history records? This operation can not be undone.", comment: "")
alert.addButton(withTitle: NSLocalizedString("Delete", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
guard let window = NSApp.keyWindow else {
return
}
alert.beginSheetModal(for: window) { resp in
guard resp == .alertFirstButtonReturn else {
return
}
actionManager.histories = []
}
}
}
struct HistoryRecordView: View {
let record: ActionManager.HistoryElement
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text("Pasteboard Event")
.font(.system(.subheadline, design: .monospaced))
.bold()
Text("Length: \(record.event.content.count) Action Candidates: \(record.actionCandidates.count)")
if !record.succeedAction.isEmpty {
Divider()
ForEach(record.succeedAction) { item in
Text("+ [\(ActionManager.shared[item.action]?.name ?? "Deleted Action")]")
Text(" Post Action: \(item.recipeAction)")
ScrollView(.horizontal, showsIndicators: false) {
Text(" Content: \(item.recipeContent)").lineLimit(1)
}
}
.foregroundColor(.blue)
}
if !record.failedAction.isEmpty {
Divider()
ForEach(record.failedAction) { item in
Text("- [\(ActionManager.shared[item.action]?.name ?? "Deleted Action")]")
Text(" \(item.errorHint)")
}
.foregroundColor(.pink)
}
Divider()
Text(record.date.formatted(date: .complete, time: .complete))
.opacity(0.5)
}
.font(.system(.footnote, design: .monospaced))
.frame(maxWidth: .infinity, alignment: .leading)
}
}
================================================
FILE: App/Action/Action/Interface/Generic/LicenseView.swift
================================================
//
// LicenseView.swift
// Action
//
// Created by Lakr Aream on 2022/8/17.
//
import SwiftUI
struct LicenseView: View {
@State var agreed = false
@Environment(\.presentationMode) var presentationMode
var licenseText: String {
guard let url = Bundle.main.url(forResource: "License", withExtension: "txt"),
let text = try? String(contentsOfFile: url.path)
else {
return "This app's bundle is broken, do not use it."
}
return text
}
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Label("Software License", systemImage: "flag.2.crossed")
.font(.system(.headline, design: .rounded))
Divider()
ScrollView {
Text(licenseText)
.font(.system(.subheadline, design: .rounded))
}
.frame(maxHeight: 250)
Divider()
HStack {
Toggle("I understand and agree to this license.", isOn: $agreed)
Spacer()
Button("Done") {
ActionApp.agreeToLicense = agreed
presentationMode.wrappedValue.dismiss()
}
.disabled(!agreed)
.buttonStyle(.borderedProminent)
.keyboardShortcut(.defaultAction)
}
}
.padding()
.task {
agreed = ActionApp.agreeToLicense
}
.onChange(of: agreed) { newValue in
if !newValue {
ActionApp.agreeToLicense = false
}
}
.frame(width: 450, alignment: .center)
}
}
================================================
FILE: App/Action/Action/Interface/Generic/MainView.swift
================================================
//
// ContentView.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import SwiftUI
struct MainView: View {
@State var openArgumentsSeet: Bool = false
var body: some View {
NavigationView {
SidebarView()
WelcomeView()
}
.navigationTitle("Action Bee")
.toolbar {
ToolbarItem(placement: .navigation) {
Button {
NSApp.keyWindow?.firstResponder?.tryToPerform(
#selector(NSSplitViewController.toggleSidebar(_:)),
with: nil
)
} label: {
Label("Toggle Sidebar", systemImage: "sidebar.leading")
}
}
}
.sheet(isPresented: $openArgumentsSeet) {
LicenseView()
}
.task {
_ = Menubar.shared
}
.task {
checkRequirements()
}
.onChange(of: openArgumentsSeet) { newValue in
if !newValue { checkRequirements() }
}
}
func checkRequirements() {
guard ActionApp.agreeToLicense else {
openArgumentsSeet = true
return
}
}
}
================================================
FILE: App/Action/Action/Interface/Generic/SettingView.swift
================================================
//
// SettingView.swift
// Action
//
// Created by Lakr Aream on 2022/8/17.
//
import SwiftUI
struct SettingView: View {
@StateObject var config = Config.shared
@State var showLicense = false
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 10) {
Section {
Toggle("Pasteboard Deduplicate", isOn: $config.pasteboardDeduplicate)
.font(.subheadline)
Text("Pasteboard content matches previous will not generate event if on")
.font(.footnote)
Toggle("Silent Mode", isOn: $config.silentMode)
.font(.subheadline)
Text("Do not show popover after action triggered")
.font(.footnote)
Toggle("Toast Mode", isOn: $config.toastMode)
.font(.subheadline)
.disabled(config.silentMode)
Text("Use toast instead of popover on menubar")
.font(.footnote)
.opacity(config.silentMode ? 0.25 : 1)
Toggle("Reduced UI Effects", isOn: $config.reducedEffects)
.font(.subheadline)
Text("Turning off visual effects does not affect app's core functionality")
.font(.footnote)
} header: {
Text("Application")
.font(.system(.headline, design: .rounded))
} footer: {
Divider()
}
Label("EOF", systemImage: "text.append")
.font(.system(.caption2, design: .rounded))
}
.padding(10)
}
.toolbar {
ToolbarItem {
Button {
NSWorkspace.shared.open(URL(string: "https://github.com/Lakr233/ActionBee")!)
} label: {
Label("Get Source Code", systemImage: "chevron.left.forwardslash.chevron.right")
}
}
ToolbarItem {
Button {
showLicense = true
} label: {
Label("License", systemImage: "flag.2.crossed")
}
.sheet(isPresented: $showLicense) {
LicenseView()
}
}
}
.navigationTitle("Setting")
.usePreferredContentSize()
}
}
================================================
FILE: App/Action/Action/Interface/Generic/SidebarView.swift
================================================
//
// SidebarView.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import SwiftUI
#if DEBUG
private let stubNavigationTarget: some View = Text("Hello World")
.usePreferredContentSize()
#endif
struct SidebarView: View {
var body: some View {
List {
Section("App") {
NavigationLink {
WelcomeView()
} label: {
Label("Welcome", systemImage: "sun.min.fill")
}
}
Section("Action") {
NavigationLink {
ModuleManageView()
} label: {
Label("Module", systemImage: "tray.full")
}
NavigationLink {
HistoryView()
} label: {
Label("History", systemImage: "clock")
}
}
Section("Misc") {
NavigationLink {
SettingView()
} label: {
Label("Setting", systemImage: "gear")
}
NavigationLink {
DiagnosticLogView()
} label: {
Label("Diagnostic", systemImage: "heart.text.square")
}
}
}
.listStyle(SidebarListStyle())
}
}
================================================
FILE: App/Action/Action/Interface/Generic/WelcomeView.swift
================================================
//
// WelcomeView.swift
// Action
//
// Created by Lakr Aream on 2022/7/25.
//
import Colorful
import SwiftUI
struct WelcomeView: View {
@State var config = Config.shared
var version: String {
var ret = "Version: " +
(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown")
+ " Build: " +
(Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown")
#if DEBUG
ret = "👾 \(ret) 👾"
#endif
return ret
}
var body: some View {
ZStack {
if !config.reducedEffects {
ColorfulView(colors: [.accentColor], colorCount: 4)
.ignoresSafeArea()
}
VStack(spacing: 4) {
Image("Avatar")
.antialiased(true)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 128, height: 128)
Spacer().frame(height: 16)
Text("Welcome to Action Bee")
.font(.system(.headline, design: .rounded))
Text("A programmable pasteboard action trigger.")
.font(.system(.body, design: .rounded))
Spacer().frame(height: 24)
}
VStack {
Spacer()
Text(version)
.font(.system(size: 12, weight: .semibold, design: .rounded))
.opacity(0.5)
}
}
.padding()
.navigationTitle("Action Bee")
.usePreferredContentSize()
}
}
================================================
FILE: App/Action/Action/Interface/Menubar/Menubar.swift
================================================
//
// Menubar.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import Cocoa
import SwiftUI
class Menubar: ObservableObject {
static let shared = Menubar()
var popover: NSPopover
var statusItem: NSStatusItem?
var eventMonitor: EventMonitor?
private init() {
let statusItem = NSStatusBar
.system
.statusItem(withLength: NSStatusItem.variableLength)
statusItem.button?.action = #selector(togglePopover(sender:))
self.statusItem = statusItem
let buildPopover = NSPopover()
popover = buildPopover
let view = MenubarView()
buildPopover.contentViewController = NSHostingController(rootView: view)
eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown], handler: mouseEventHandler)
statusItem.button?.title = "🎉"
statusItem.button?.target = self
}
func showPopover(_: AnyObject? = nil) {
if let statusBarButton = statusItem?.button {
popover.show(relativeTo: statusBarButton.bounds, of: statusBarButton, preferredEdge: NSRectEdge.maxY)
eventMonitor?.start()
}
}
func hidePopover(_ sender: AnyObject? = nil) {
popover.performClose(sender)
eventMonitor?.stop()
}
func mouseEventHandler(_ event: NSEvent?) {
if popover.isShown, let event = event {
hidePopover(event)
}
}
@objc
func togglePopover(sender: AnyObject) {
if popover.isShown {
hidePopover(sender)
} else {
showPopover(sender)
}
}
enum TitleType: String {
case ready = "🎉"
case running = "💨"
}
private let titleThrottle = Throttle(minimumDelay: 0.5, queue: .main)
func switchTitle(status: TitleType) {
titleThrottle.throttle {
self.statusItem?.button?.title = status.rawValue
}
}
}
extension Menubar {
class EventMonitor {
private var monitor: Any?
private let mask: NSEvent.EventTypeMask
private let handler: (NSEvent?) -> Void
public init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) {
self.mask = mask
self.handler = handler
}
deinit {
stop()
}
public func start() {
monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) as! NSObject
}
public func stop() {
if monitor != nil {
NSEvent.removeMonitor(monitor!)
monitor = nil
}
}
}
}
================================================
FILE: App/Action/Action/Interface/Menubar/MenubarView.swift
================================================
//
// MenubarView.swift
// Action
//
// Created by Lakr Aream on 2022/8/16.
//
import Colorful
import SwiftUI
struct MenubarView: View {
@StateObject var menubar = Menubar.shared
@StateObject var actionManager = ActionManager.shared
var lastHistory: ActionManager.HistoryElement? {
if let last = actionManager.histories.last,
last.date > ActionApp.bootTime
{
return last
}
return nil
}
var body: some View {
ZStack {
if actionManager.actionRunning {
ZStack {
VStack(spacing: 20) {
ProgressView()
Text(actionManager.actionRunningHint)
.font(.system(.subheadline, design: .monospaced))
}
}
.frame(width: 400, height: 200)
} else if let lastHistory = lastHistory {
VStack {
Spacer().frame(height: 16)
Image(
systemName: lastHistory.failedAction.isEmpty
? "checkmark.circle.fill"
: "checkmark.circle.trianglebadge.exclamationmark"
)
.foregroundColor(lastHistory.failedAction.isEmpty ? .green : .orange)
.font(.system(size: 36, weight: .semibold, design: .rounded))
Spacer().frame(height: 16)
HistoryRecordView(record: lastHistory)
Divider().hidden()
}
.padding()
.frame(width: 400)
} else {
VStack(alignment: .leading, spacing: 8) {
Image("Avatar")
.antialiased(true)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 50, height: 50)
HStack {
Image(systemName: "circle.fill")
.font(.headline)
.foregroundColor(.green)
Text("ActionBee is ready to accept pasteboard events.")
.font(.headline)
}
RandomCodeTextView()
Divider().hidden()
}
.padding()
.frame(width: 400, height: 200)
}
}
}
}
================================================
FILE: App/Action/Action/Interface/Toast/Toast.swift
================================================
//
// Toast.swift
// Action
//
// Created by Lakr Aream on 2022/8/17.
//
import Cocoa
import Foundation
import SwiftUI
private class ToastWindow: NSWindow {
init(with screen: NSScreen) {
super.init(
contentRect: screen.frame,
styleMask: [.borderless, .fullSizeContentView],
backing: .buffered,
defer: false
)
isOpaque = false
alphaValue = 1
titleVisibility = .hidden
titlebarAppearsTransparent = true
backgroundColor = .clear
ignoresMouseEvents = true
isMovable = false
isMovableByWindowBackground = false
// .fullScreenAuxiliary .stationary .canJoinAllSpaces
collectionBehavior = NSWindow.CollectionBehavior(rawValue: 273)
styleMask = .borderless
// The standard ScreenSaverView class actually sets the window
// level to 2002, not the 1000 defined by NSScreenSaverWindowLevel
// and kCGScreenSaverWindowLevel
/// https://github.com/genekogan/ofxScreenGrab/blob/master/src/macGlutfix.m
level = NSWindow.Level(rawValue: 2005)
setFrameOrigin(screen.frame.origin)
makeKeyAndOrderFront(nil)
hasShadow = false
}
}
private class ToastWindowController: NSWindowController {
init(with screen: NSScreen, systemIcon: String, message: String) {
super.init(window: ToastWindow(with: screen))
contentViewController = NSHostingController(
rootView: ToastView(systemIcon: systemIcon, message: message)
)
}
@available(*, unavailable)
required init(coder _: NSCoder) {
fatalError()
}
}
struct ToastView: View {
let systemIcon: String
let message: String
@State var opacity: Double = 1
var body: some View {
GeometryReader { _ in
HStack {
Spacer()
VStack {
Spacer()
Spacer()
Spacer()
Spacer()
content
Spacer()
}
Spacer()
}
}
.opacity(opacity)
.animation(.interactiveSpring(), value: opacity)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
opacity = 0
}
}
}
var content: some View {
VStack(alignment: .center, spacing: 12) {
Image(systemName: systemIcon)
.font(.system(size: 36, weight: .bold, design: .rounded))
Text(message)
.font(.system(.headline, design: .rounded))
}
.padding()
.background(.regularMaterial)
.cornerRadius(8)
}
}
enum Toast {
static func post(systemIcon: String, message: String) {
guard let screen = NSScreen.main else {
return
}
let windowController = ToastWindowController(
with: screen,
systemIcon: systemIcon,
message: message
)
windowController.window?.setFrameOrigin(screen.frame.origin)
windowController.window?.setContentSize(screen.frame.size)
windowController.window?.makeKeyAndOrderFront(nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
windowController.window?.close()
}
}
}
================================================
FILE: App/Action/Action.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
13C6C62128AF1BF0008ADA60 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 13C6C62328AF1BF0008ADA60 /* Localizable.strings */; };
1F6BCF0628B219B400C2B417 /* Template+Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6BCF0528B219B400C2B417 /* Template+Node.swift */; };
5001740128AA557100FF9B99 /* UserDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5001740028AA557100FF9B99 /* UserDefault.swift */; };
5001740528AA818500FF9B99 /* DiagnosticLogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5001740428AA818500FF9B99 /* DiagnosticLogView.swift */; };
5006F55E28A9663100C8ADBE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5006F55D28A9663100C8ADBE /* Notification.swift */; };
5006F56028A9683C00C8ADBE /* DispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5006F55F28A9683C00C8ADBE /* DispatchQueue.swift */; };
502D1F0A28A8F88D0022CCD3 /* ActionTemplates in Resources */ = {isa = PBXBuildFile; fileRef = 502D1F0928A8F88D0022CCD3 /* ActionTemplates */; };
502E87A328AA954500CAB5E1 /* ModuleEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502E87A228AA954500CAB5E1 /* ModuleEditView.swift */; };
502E87A528AA95BF00CAB5E1 /* ModuleElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502E87A428AA95BF00CAB5E1 /* ModuleElementView.swift */; };
5030D80828ABDD72001A96B5 /* ActionManager+History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5030D80728ABDD72001A96B5 /* ActionManager+History.swift */; };
5030D80A28ABE953001A96B5 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5030D80928ABE953001A96B5 /* HistoryView.swift */; };
5030D80C28ABEF64001A96B5 /* ApplicationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5030D80B28ABEF64001A96B5 /* ApplicationView.swift */; };
5030D80E28ABFA82001A96B5 /* SettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5030D80D28ABFA82001A96B5 /* SettingView.swift */; };
5030D81028AC0045001A96B5 /* LicenseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5030D80F28AC0045001A96B5 /* LicenseView.swift */; };
5030D81228AC01A7001A96B5 /* License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5030D81128AC01A7001A96B5 /* License.txt */; };
5030D81628AC090A001A96B5 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5030D81528AC090A001A96B5 /* Config.swift */; };
503976FA28AE143600588622 /* ModuleImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503976F928AE143600588622 /* ModuleImportView.swift */; };
5053CF85288F724E00A92822 /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053CF84288F724E00A92822 /* Executor.swift */; };
5053CF87288F764000A92822 /* ModuleManageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053CF86288F764000A92822 /* ModuleManageView.swift */; };
5053CF8A288F76E700A92822 /* PasteboardManager+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053CF89288F76E700A92822 /* PasteboardManager+Event.swift */; };
5053CF91288F776000A92822 /* ActionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053CF90288F776000A92822 /* ActionManager.swift */; };
5053CF93288F788B00A92822 /* ActionManager+Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053CF92288F788B00A92822 /* ActionManager+Module.swift */; };
5053CF9A288F9A5E00A92822 /* ModuleCreateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053CF99288F9A5E00A92822 /* ModuleCreateView.swift */; };
5053CF9C288F9D8700A92822 /* SymbolPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 5053CF9B288F9D8700A92822 /* SymbolPicker */; };
505A10A828A95EC200D46DB3 /* ActionManager+Template.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505A10A728A95EC200D46DB3 /* ActionManager+Template.swift */; };
5067392628AB786A003A6A9C /* Template+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067392528AB786A003A6A9C /* Template+Swift.swift */; };
5067392B28AB7A51003A6A9C /* ActionManager+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067392A28AB7A51003A6A9C /* ActionManager+Event.swift */; };
5067392D28AB7D6C003A6A9C /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067392C28AB7D6C003A6A9C /* Result.swift */; };
5067393228AB8E55003A6A9C /* RandomCodeTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067393128AB8E55003A6A9C /* RandomCodeTextView.swift */; };
5067393428ABA328003A6A9C /* ActionManager+Artifact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067393328ABA328003A6A9C /* ActionManager+Artifact.swift */; };
5067393628ABA422003A6A9C /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 5067393528ABA422003A6A9C /* KeychainAccess */; };
5067393828ABA445003A6A9C /* AES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067393728ABA445003A6A9C /* AES.swift */; };
5067393C28ABA89D003A6A9C /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067393B28ABA89D003A6A9C /* Data.swift */; };
5067394128ABC9C3003A6A9C /* Menubar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067394028ABC9C3003A6A9C /* Menubar.swift */; };
5067394328ABCB18003A6A9C /* MenubarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5067394228ABCB18003A6A9C /* MenubarView.swift */; };
507137EC288E934000C23E7F /* ActionApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507137EB288E934000C23E7F /* ActionApp.swift */; };
507137EE288E934000C23E7F /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507137ED288E934000C23E7F /* MainView.swift */; };
507137F0288E934100C23E7F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 507137EF288E934100C23E7F /* Assets.xcassets */; };
507137FC288E935A00C23E7F /* AuxiliaryExecute in Frameworks */ = {isa = PBXBuildFile; productRef = 507137FB288E935A00C23E7F /* AuxiliaryExecute */; };
507137FE288E935A00C23E7F /* Colorful in Frameworks */ = {isa = PBXBuildFile; productRef = 507137FD288E935A00C23E7F /* Colorful */; };
50713803288E976600C23E7F /* AppSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50713802288E976600C23E7F /* AppSetup.swift */; };
50713808288E9C0C00C23E7F /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50713807288E9C0C00C23E7F /* View.swift */; };
5071380A288E9C8100C23E7F /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50713809288E9C8100C23E7F /* WelcomeView.swift */; };
5071380C288E9C8800C23E7F /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5071380B288E9C8800C23E7F /* SidebarView.swift */; };
5071380E288E9D8A00C23E7F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5071380D288E9D8A00C23E7F /* AppDelegate.swift */; };
50A7D7FE28ACCB4C004F0B34 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A7D7FD28ACCB4C004F0B34 /* Throttle.swift */; };
50A7D80128ACCE23004F0B34 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A7D80028ACCE23004F0B34 /* Toast.swift */; };
50A7D80328ACD14B004F0B34 /* Template+Executable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A7D80228ACD14B004F0B34 /* Template+Executable.swift */; };
50BCF6AC288EE81000A97B4C /* PasteboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BCF6AB288EE81000A97B4C /* PasteboardManager.swift */; };
50BCF6AE288F01EF00A97B4C /* StatusBarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BCF6AD288F01EF00A97B4C /* StatusBarManager.swift */; };
50E5204228BE04FC00C3228F /* Template+Python.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E5204128BE04FC00C3228F /* Template+Python.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
13C6C62228AF1BF0008ADA60 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; };
13C6C62428AF1DEB008ADA60 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; };
1F6BCF0528B219B400C2B417 /* Template+Node.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Template+Node.swift"; sourceTree = ""; };
5001740028AA557100FF9B99 /* UserDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefault.swift; sourceTree = ""; };
5001740428AA818500FF9B99 /* DiagnosticLogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiagnosticLogView.swift; sourceTree = ""; };
5006F55D28A9663100C8ADBE /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; };
5006F55F28A9683C00C8ADBE /* DispatchQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchQueue.swift; sourceTree = ""; };
502D1F0928A8F88D0022CCD3 /* ActionTemplates */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ActionTemplates; sourceTree = ""; };
502E87A228AA954500CAB5E1 /* ModuleEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleEditView.swift; sourceTree = ""; };
502E87A428AA95BF00CAB5E1 /* ModuleElementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleElementView.swift; sourceTree = ""; };
5030D80728ABDD72001A96B5 /* ActionManager+History.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionManager+History.swift"; sourceTree = ""; };
5030D80928ABE953001A96B5 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = ""; };
5030D80B28ABEF64001A96B5 /* ApplicationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationView.swift; sourceTree = ""; };
5030D80D28ABFA82001A96B5 /* SettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingView.swift; sourceTree = ""; };
5030D80F28AC0045001A96B5 /* LicenseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicenseView.swift; sourceTree = ""; };
5030D81128AC01A7001A96B5 /* License.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = License.txt; sourceTree = ""; };
5030D81528AC090A001A96B5 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; };
503976F928AE143600588622 /* ModuleImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleImportView.swift; sourceTree = ""; };
5053CF84288F724E00A92822 /* Executor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Executor.swift; sourceTree = ""; };
5053CF86288F764000A92822 /* ModuleManageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleManageView.swift; sourceTree = ""; };
5053CF89288F76E700A92822 /* PasteboardManager+Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PasteboardManager+Event.swift"; sourceTree = ""; };
5053CF90288F776000A92822 /* ActionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionManager.swift; sourceTree = ""; };
5053CF92288F788B00A92822 /* ActionManager+Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionManager+Module.swift"; sourceTree = ""; };
5053CF99288F9A5E00A92822 /* ModuleCreateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleCreateView.swift; sourceTree = ""; };
505A10A728A95EC200D46DB3 /* ActionManager+Template.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionManager+Template.swift"; sourceTree = ""; };
5067392528AB786A003A6A9C /* Template+Swift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Template+Swift.swift"; sourceTree = ""; };
5067392A28AB7A51003A6A9C /* ActionManager+Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionManager+Event.swift"; sourceTree = ""; };
5067392C28AB7D6C003A6A9C /* Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; };
5067393128AB8E55003A6A9C /* RandomCodeTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomCodeTextView.swift; sourceTree = ""; };
5067393328ABA328003A6A9C /* ActionManager+Artifact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionManager+Artifact.swift"; sourceTree = ""; };
5067393728ABA445003A6A9C /* AES.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AES.swift; sourceTree = ""; };
5067393B28ABA89D003A6A9C /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; };
5067394028ABC9C3003A6A9C /* Menubar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menubar.swift; sourceTree = ""; };
5067394228ABCB18003A6A9C /* MenubarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarView.swift; sourceTree = ""; };
507137E8288E934000C23E7F /* Action.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Action.app; sourceTree = BUILT_PRODUCTS_DIR; };
507137EB288E934000C23E7F /* ActionApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionApp.swift; sourceTree = ""; };
507137ED288E934000C23E7F /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; };
507137EF288E934100C23E7F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
507137F4288E934100C23E7F /* Action.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Action.entitlements; sourceTree = ""; };
50713802288E976600C23E7F /* AppSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSetup.swift; sourceTree = ""; };
50713807288E9C0C00C23E7F /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; };
50713809288E9C8100C23E7F /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; };
5071380B288E9C8800C23E7F /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; };
5071380D288E9D8A00C23E7F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
50A7D7FD28ACCB4C004F0B34 /* Throttle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Throttle.swift; sourceTree = ""; };
50A7D80028ACCE23004F0B34 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; };
50A7D80228ACD14B004F0B34 /* Template+Executable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Template+Executable.swift"; sourceTree = ""; };
50BCF6AB288EE81000A97B4C /* PasteboardManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteboardManager.swift; sourceTree = ""; };
50BCF6AD288F01EF00A97B4C /* StatusBarManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBarManager.swift; sourceTree = ""; };
50E5204128BE04FC00C3228F /* Template+Python.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Template+Python.swift"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
507137E5288E934000C23E7F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
507137FE288E935A00C23E7F /* Colorful in Frameworks */,
507137FC288E935A00C23E7F /* AuxiliaryExecute in Frameworks */,
5053CF9C288F9D8700A92822 /* SymbolPicker in Frameworks */,
5067393628ABA422003A6A9C /* KeychainAccess in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
502E87A628AA95DF00CAB5E1 /* ActionModule */ = {
isa = PBXGroup;
children = (
5053CF86288F764000A92822 /* ModuleManageView.swift */,
503976F928AE143600588622 /* ModuleImportView.swift */,
502E87A428AA95BF00CAB5E1 /* ModuleElementView.swift */,
5053CF99288F9A5E00A92822 /* ModuleCreateView.swift */,
502E87A228AA954500CAB5E1 /* ModuleEditView.swift */,
);
path = ActionModule;
sourceTree = "";
};
502E87A728AA95E800CAB5E1 /* Generic */ = {
isa = PBXGroup;
children = (
507137ED288E934000C23E7F /* MainView.swift */,
5071380B288E9C8800C23E7F /* SidebarView.swift */,
50713809288E9C8100C23E7F /* WelcomeView.swift */,
5030D80928ABE953001A96B5 /* HistoryView.swift */,
5030D80D28ABFA82001A96B5 /* SettingView.swift */,
5001740428AA818500FF9B99 /* DiagnosticLogView.swift */,
5030D80F28AC0045001A96B5 /* LicenseView.swift */,
5030D80B28ABEF64001A96B5 /* ApplicationView.swift */,
);
path = Generic;
sourceTree = "";
};
5030D81428AC08FC001A96B5 /* Config */ = {
isa = PBXGroup;
children = (
5030D81528AC090A001A96B5 /* Config.swift */,
);
path = Config;
sourceTree = "";
};
5053CF88288F76CC00A92822 /* PasteboardManager */ = {
isa = PBXGroup;
children = (
50BCF6AB288EE81000A97B4C /* PasteboardManager.swift */,
5053CF89288F76E700A92822 /* PasteboardManager+Event.swift */,
);
path = PasteboardManager;
sourceTree = "";
};
5053CF8B288F770B00A92822 /* StatusBarManager */ = {
isa = PBXGroup;
children = (
50BCF6AD288F01EF00A97B4C /* StatusBarManager.swift */,
);
path = StatusBarManager;
sourceTree = "";
};
5053CF8C288F771500A92822 /* Executor */ = {
isa = PBXGroup;
children = (
5053CF84288F724E00A92822 /* Executor.swift */,
);
path = Executor;
sourceTree = "";
};
5053CF8D288F771C00A92822 /* Action */ = {
isa = PBXGroup;
children = (
5053CF90288F776000A92822 /* ActionManager.swift */,
5030D80728ABDD72001A96B5 /* ActionManager+History.swift */,
5053CF92288F788B00A92822 /* ActionManager+Module.swift */,
5067393328ABA328003A6A9C /* ActionManager+Artifact.swift */,
5067392A28AB7A51003A6A9C /* ActionManager+Event.swift */,
5067392728AB78CD003A6A9C /* ActionModuleTemplates */,
502D1F0928A8F88D0022CCD3 /* ActionTemplates */,
);
path = Action;
sourceTree = "";
};
5067392728AB78CD003A6A9C /* ActionModuleTemplates */ = {
isa = PBXGroup;
children = (
505A10A728A95EC200D46DB3 /* ActionManager+Template.swift */,
50A7D80228ACD14B004F0B34 /* Template+Executable.swift */,
5067392528AB786A003A6A9C /* Template+Swift.swift */,
1F6BCF0528B219B400C2B417 /* Template+Node.swift */,
50E5204128BE04FC00C3228F /* Template+Python.swift */,
);
path = ActionModuleTemplates;
sourceTree = "";
};
5067393028AB8E42003A6A9C /* Effect */ = {
isa = PBXGroup;
children = (
5067393128AB8E55003A6A9C /* RandomCodeTextView.swift */,
);
path = Effect;
sourceTree = "";
};
5067393F28ABC9B1003A6A9C /* Menubar */ = {
isa = PBXGroup;
children = (
5067394028ABC9C3003A6A9C /* Menubar.swift */,
5067394228ABCB18003A6A9C /* MenubarView.swift */,
);
path = Menubar;
sourceTree = "";
};
507137DF288E934000C23E7F = {
isa = PBXGroup;
children = (
507137EA288E934000C23E7F /* Action */,
507137E9288E934000C23E7F /* Products */,
507137FA288E935A00C23E7F /* Frameworks */,
);
sourceTree = "";
};
507137E9288E934000C23E7F /* Products */ = {
isa = PBXGroup;
children = (
507137E8288E934000C23E7F /* Action.app */,
);
name = Products;
sourceTree = "";
};
507137EA288E934000C23E7F /* Action */ = {
isa = PBXGroup;
children = (
50713801288E975200C23E7F /* Application */,
50BCF6AA288EE7F900A97B4C /* Backend */,
50713805288E9B5200C23E7F /* Interface */,
50713806288E9C0100C23E7F /* Extension */,
);
path = Action;
sourceTree = "";
};
507137FA288E935A00C23E7F /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
50713801288E975200C23E7F /* Application */ = {
isa = PBXGroup;
children = (
13C6C62328AF1BF0008ADA60 /* Localizable.strings */,
507137EB288E934000C23E7F /* ActionApp.swift */,
507137F4288E934100C23E7F /* Action.entitlements */,
507137EF288E934100C23E7F /* Assets.xcassets */,
5030D81128AC01A7001A96B5 /* License.txt */,
50713802288E976600C23E7F /* AppSetup.swift */,
5071380D288E9D8A00C23E7F /* AppDelegate.swift */,
);
path = Application;
sourceTree = "";
};
50713805288E9B5200C23E7F /* Interface */ = {
isa = PBXGroup;
children = (
502E87A628AA95DF00CAB5E1 /* ActionModule */,
5067393028AB8E42003A6A9C /* Effect */,
502E87A728AA95E800CAB5E1 /* Generic */,
5067393F28ABC9B1003A6A9C /* Menubar */,
50A7D7FF28ACCE18004F0B34 /* Toast */,
);
path = Interface;
sourceTree = "";
};
50713806288E9C0100C23E7F /* Extension */ = {
isa = PBXGroup;
children = (
5067393728ABA445003A6A9C /* AES.swift */,
5067393B28ABA89D003A6A9C /* Data.swift */,
5006F55F28A9683C00C8ADBE /* DispatchQueue.swift */,
5006F55D28A9663100C8ADBE /* Notification.swift */,
5067392C28AB7D6C003A6A9C /* Result.swift */,
5001740028AA557100FF9B99 /* UserDefault.swift */,
50713807288E9C0C00C23E7F /* View.swift */,
50A7D7FD28ACCB4C004F0B34 /* Throttle.swift */,
);
path = Extension;
sourceTree = "";
};
50A7D7FF28ACCE18004F0B34 /* Toast */ = {
isa = PBXGroup;
children = (
50A7D80028ACCE23004F0B34 /* Toast.swift */,
);
path = Toast;
sourceTree = "";
};
50BCF6AA288EE7F900A97B4C /* Backend */ = {
isa = PBXGroup;
children = (
5053CF8D288F771C00A92822 /* Action */,
5030D81428AC08FC001A96B5 /* Config */,
5053CF8C288F771500A92822 /* Executor */,
5053CF88288F76CC00A92822 /* PasteboardManager */,
5053CF8B288F770B00A92822 /* StatusBarManager */,
);
path = Backend;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
507137E7288E934000C23E7F /* Action */ = {
isa = PBXNativeTarget;
buildConfigurationList = 507137F7288E934100C23E7F /* Build configuration list for PBXNativeTarget "Action" */;
buildPhases = (
507137FF288E93A600C23E7F /* Swift Format */,
502D1F0B28A8FA910022CCD3 /* Update Action Templates */,
5030D81328AC022A001A96B5 /* Scan License */,
507137E4288E934000C23E7F /* Sources */,
507137E5288E934000C23E7F /* Frameworks */,
507137E6288E934000C23E7F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Action;
packageProductDependencies = (
507137FB288E935A00C23E7F /* AuxiliaryExecute */,
507137FD288E935A00C23E7F /* Colorful */,
5053CF9B288F9D8700A92822 /* SymbolPicker */,
5067393528ABA422003A6A9C /* KeychainAccess */,
);
productName = Action;
productReference = 507137E8288E934000C23E7F /* Action.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
507137E0288E934000C23E7F /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
507137E7288E934000C23E7F = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 507137E3288E934000C23E7F /* Build configuration list for PBXProject "Action" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
"zh-Hans",
);
mainGroup = 507137DF288E934000C23E7F;
productRefGroup = 507137E9288E934000C23E7F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
507137E7288E934000C23E7F /* Action */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
507137E6288E934000C23E7F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
502D1F0A28A8F88D0022CCD3 /* ActionTemplates in Resources */,
13C6C62128AF1BF0008ADA60 /* Localizable.strings in Resources */,
507137F0288E934100C23E7F /* Assets.xcassets in Resources */,
5030D81228AC01A7001A96B5 /* License.txt in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
502D1F0B28A8FA910022CCD3 /* Update Action Templates */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Update Action Templates";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "$SOURCE_ROOT/../../Resources/Scripts/PackTemplates.sh\n";
};
5030D81328AC022A001A96B5 /* Scan License */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Scan License";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "$SOURCE_ROOT/../../Resources/Scripts/UpdateLicenses.sh\n";
};
507137FF288E93A600C23E7F /* Swift Format */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Swift Format";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "cd $SOURCE_ROOT\npwd\n\nif ! command -v \"swiftformat\" &> /dev/null\nthen\n echo \"swiftformat could not be found, skipping\"\n exit 0\nfi\n\nswiftformat . --swiftversion 5.6\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
507137E4288E934000C23E7F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50E5204228BE04FC00C3228F /* Template+Python.swift in Sources */,
50BCF6AE288F01EF00A97B4C /* StatusBarManager.swift in Sources */,
503976FA28AE143600588622 /* ModuleImportView.swift in Sources */,
5067393C28ABA89D003A6A9C /* Data.swift in Sources */,
5030D81028AC0045001A96B5 /* LicenseView.swift in Sources */,
50A7D80328ACD14B004F0B34 /* Template+Executable.swift in Sources */,
5053CF8A288F76E700A92822 /* PasteboardManager+Event.swift in Sources */,
5006F56028A9683C00C8ADBE /* DispatchQueue.swift in Sources */,
5030D80E28ABFA82001A96B5 /* SettingView.swift in Sources */,
5001740528AA818500FF9B99 /* DiagnosticLogView.swift in Sources */,
5071380A288E9C8100C23E7F /* WelcomeView.swift in Sources */,
5030D80A28ABE953001A96B5 /* HistoryView.swift in Sources */,
5030D80828ABDD72001A96B5 /* ActionManager+History.swift in Sources */,
502E87A328AA954500CAB5E1 /* ModuleEditView.swift in Sources */,
5067392628AB786A003A6A9C /* Template+Swift.swift in Sources */,
50713808288E9C0C00C23E7F /* View.swift in Sources */,
507137EE288E934000C23E7F /* MainView.swift in Sources */,
5001740128AA557100FF9B99 /* UserDefault.swift in Sources */,
50A7D80128ACCE23004F0B34 /* Toast.swift in Sources */,
50A7D7FE28ACCB4C004F0B34 /* Throttle.swift in Sources */,
5067393828ABA445003A6A9C /* AES.swift in Sources */,
50713803288E976600C23E7F /* AppSetup.swift in Sources */,
5071380E288E9D8A00C23E7F /* AppDelegate.swift in Sources */,
5053CF85288F724E00A92822 /* Executor.swift in Sources */,
5067392D28AB7D6C003A6A9C /* Result.swift in Sources */,
5067394128ABC9C3003A6A9C /* Menubar.swift in Sources */,
5053CF91288F776000A92822 /* ActionManager.swift in Sources */,
5053CF93288F788B00A92822 /* ActionManager+Module.swift in Sources */,
5030D80C28ABEF64001A96B5 /* ApplicationView.swift in Sources */,
5067392B28AB7A51003A6A9C /* ActionManager+Event.swift in Sources */,
507137EC288E934000C23E7F /* ActionApp.swift in Sources */,
5067394328ABCB18003A6A9C /* MenubarView.swift in Sources */,
5006F55E28A9663100C8ADBE /* Notification.swift in Sources */,
5067393228AB8E55003A6A9C /* RandomCodeTextView.swift in Sources */,
5071380C288E9C8800C23E7F /* SidebarView.swift in Sources */,
5030D81628AC090A001A96B5 /* Config.swift in Sources */,
5067393428ABA328003A6A9C /* ActionManager+Artifact.swift in Sources */,
50BCF6AC288EE81000A97B4C /* PasteboardManager.swift in Sources */,
5053CF87288F764000A92822 /* ModuleManageView.swift in Sources */,
502E87A528AA95BF00CAB5E1 /* ModuleElementView.swift in Sources */,
5053CF9A288F9A5E00A92822 /* ModuleCreateView.swift in Sources */,
505A10A828A95EC200D46DB3 /* ActionManager+Template.swift in Sources */,
1F6BCF0628B219B400C2B417 /* Template+Node.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
13C6C62328AF1BF0008ADA60 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
13C6C62228AF1BF0008ADA60 /* en */,
13C6C62428AF1DEB008ADA60 /* zh-Hans */,
);
name = Localizable.strings;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
507137F5288E934100C23E7F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
507137F6288E934100C23E7F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
507137F8288E934100C23E7F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Action/Action.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 4;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = M4Z5DVY94F;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "Action Bee";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Lakr Aream. All Rights Reserved.";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.0;
MARKETING_VERSION = 1.5;
PRODUCT_BUNDLE_IDENTIFIER = wiki.qaq.Action;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
507137F9288E934100C23E7F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Action/Action.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 4;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = M4Z5DVY94F;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "Action Bee";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Lakr Aream. All Rights Reserved.";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.0;
MARKETING_VERSION = 1.5;
PRODUCT_BUNDLE_IDENTIFIER = wiki.qaq.Action;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
507137E3288E934000C23E7F /* Build configuration list for PBXProject "Action" */ = {
isa = XCConfigurationList;
buildConfigurations = (
507137F5288E934100C23E7F /* Debug */,
507137F6288E934100C23E7F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
507137F7288E934100C23E7F /* Build configuration list for PBXNativeTarget "Action" */ = {
isa = XCConfigurationList;
buildConfigurations = (
507137F8288E934100C23E7F /* Debug */,
507137F9288E934100C23E7F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
5053CF9B288F9D8700A92822 /* SymbolPicker */ = {
isa = XCSwiftPackageProductDependency;
productName = SymbolPicker;
};
5067393528ABA422003A6A9C /* KeychainAccess */ = {
isa = XCSwiftPackageProductDependency;
productName = KeychainAccess;
};
507137FB288E935A00C23E7F /* AuxiliaryExecute */ = {
isa = XCSwiftPackageProductDependency;
productName = AuxiliaryExecute;
};
507137FD288E935A00C23E7F /* Colorful */ = {
isa = XCSwiftPackageProductDependency;
productName = Colorful;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 507137E0288E934000C23E7F /* Project object */;
}
================================================
FILE: App.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: External/AuxiliaryExecute/.gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
================================================
FILE: External/AuxiliaryExecute/LICENSE
================================================
MIT License
Copyright (c) 2021 Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: External/AuxiliaryExecute/Package.swift
================================================
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "AuxiliaryExecute",
products: [
.library(
name: "AuxiliaryExecute",
targets: ["AuxiliaryExecute"]
),
],
targets: [
.target(
name: "AuxiliaryExecute",
dependencies: []
),
.testTarget(
name: "AuxiliaryExecuteTests",
dependencies: ["AuxiliaryExecute"]
),
]
)
================================================
FILE: External/AuxiliaryExecute/README.md
================================================
# AuxiliaryExecute
A Swift wrapper for system shell over posix_spawn with search path and env support.
## Usage
```
import AuxiliaryExecute
AuxiliaryExecute.local.bash(command: "echo nya")
```
## Customization & Defaults
The source for this package is well explained in details along with comments. Feel free looking for them.
```
// automatically search for binary within env PATH
let result = AuxiliaryExecute.local.shell(
command: "bash",
args: ["-c", "echo $mua"],
environment: ["mua": "nya"],
timeout: 0
) { stdout in
print(stdout)
} stderrBlock: { stderr in
print(stderr)
}
// or call with binary's full path
func spawn(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
stdoutBlock: ((String) -> Void)? = nil,
stderrBlock: ((String) -> Void)? = nil
)
// for customize option for shell
func appendSearchPath(with value: String)
func updateExtraSearchPath(with block: (inout [String]) -> Void)
func updateOverwriteTable(with block: (inout [String: String?]) -> Void)
```
## License
AuxiliaryExecute is licensed under [MIT](./LICENSE).
---
Copyright © 2021 Lakr Aream. All Rights Reserved.
================================================
FILE: External/AuxiliaryExecute/Sources/AuxiliaryExecute/AuxiliaryExecute+Async.swift
================================================
//
// AuxiliaryExecute+Spawn.swift
// AuxiliaryExecute
//
// Created by Cyandev on 2022/1/10.
//
#if swift(>=5.5)
import Foundation
@available(iOS 15.0, macOS 12.0.0, *)
public extension AuxiliaryExecute {
/// async/await function for spawn using withCheckedContinuation
/// - Parameters:
/// - command: full path of the binary file. eg: "/bin/cat"
/// - args: arg to pass to the binary, exclude argv[0] which is the path itself. eg: ["nya"]
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - stdout: a block call from pipeControlQueue in background when buffer from stdout available for read
/// - stderr: a block call from pipeControlQueue in background when buffer from stderr available for read
/// - Returns: execution recipe, see it's definition for details
@discardableResult
static func spawnAsync(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
stdoutBlock: ((String) -> Void)? = nil,
stderrBlock: ((String) -> Void)? = nil
) async -> ExecuteRecipe {
await withCheckedContinuation { cont in
self.spawn(
command: command,
args: args,
environment: environment,
timeout: timeout,
stdoutBlock: stdoutBlock,
stderrBlock: stderrBlock
) { recipe in
cont.resume(returning: recipe)
}
}
}
/// async/await function for spawn using withCheckedContinuation
/// - Parameters:
/// - command: full path of the binary file. eg: "/bin/cat"
/// - args: arg to pass to the binary, exclude argv[0] which is the path itself. eg: ["nya"]
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - output: a block call from pipeControlQueue in background when buffer from stdout or stderr available for read
/// - Returns: execution recipe, see it's definition for details
@discardableResult
static func spawnAsync(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
output: ((String) -> Void)? = nil
) async -> ExecuteRecipe {
let lock = NSLock()
return await spawnAsync(
command: command,
args: args,
environment: environment,
timeout: timeout,
stdoutBlock: { str in
lock.lock()
output?(str)
lock.unlock()
}, stderrBlock: { str in
lock.lock()
output?(str)
lock.unlock()
}
)
}
}
#endif
================================================
FILE: External/AuxiliaryExecute/Sources/AuxiliaryExecute/AuxiliaryExecute+Shell.swift
================================================
//
// AuxiliaryExecute+Shell.swift
// AuxiliaryExecute
//
// Created by Lakr Aream on 2021/12/6.
//
import Foundation
public extension AuxiliaryExecute {
/// Setup binary table, require lock
internal func setupBinaryTable() {
lock.lock()
let environmentPath = ProcessInfo
.processInfo
.environment["PATH"]?
.components(separatedBy: ":")
.compactMap { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
?? []
currentPath = environmentPath
binaryTable.removeAll()
// now, let's search inside your path and system path
for eachPath in environmentPath + extraSearchPath {
if let dirElements = try? FileManager
.default
.contentsOfDirectory(atPath: eachPath)
{
for node in dirElements {
let itemLocation = URL(fileURLWithPath: eachPath)
.appendingPathComponent(node)
if !isBinaryValid(at: itemLocation) {
continue
}
binaryTable[node] = itemLocation.path
}
}
}
lock.unlock()
}
/// append the search path, thread safe
/// - Parameter value: the path
func appendSearchPath(with value: String) {
lock.lock()
extraSearchPath.append(value)
lock.unlock()
}
/// update the customized search path, thread safe
/// - Parameter block: update inside this block
func updateExtraSearchPath(with block: (inout [String]) -> Void) {
lock.lock()
block(&extraSearchPath)
lock.unlock()
}
/// update the customized binary table, thread safe
/// - Parameter block: update inside this block
func updateOverwriteTable(with block: (inout [String: String?]) -> Void) {
lock.lock()
block(&overwriteTable)
lock.unlock()
}
/// return whether you telling us to not to find anything with this command in shell
/// - Parameter command: command name
/// - Returns: should skip search
internal func commandShouldNotExists(command: String) -> Bool {
lock.lock()
defer { lock.unlock() }
if overwriteTable.keys.contains(command) {
if let value = overwriteTable[command] {
// it is a String?? :)
return value == nil
} else {
// there must be something wrong
assertionFailure("broken memory found with overwriteTable")
return false
}
}
return false
}
/// safely grab the full path for shell command
/// - Parameter command: command name
/// - Returns: full path if exists, otherwise nil
func binaryLocationFor(command: String) -> String? {
lock.lock()
defer { lock.unlock() }
// check if you overwritten the command first
if overwriteTable.keys.contains(command) {
if let value = overwriteTable[command] {
// it is a String?? :)
// you telling us to not find anything with this command
return value
} else {
// there must be something wrong
assertionFailure("broken memory found with overwriteTable")
return nil
}
} else {
return binaryTable[command]
}
}
/// Indicate if a file has permission to execute, check's with permission
/// - Parameter at: file url
/// - Returns: able to execute or not
private func isBinaryValid(at: URL) -> Bool {
FileManager
.default
.isExecutableFile(atPath: at.path)
}
/// call a binary to execute
/// - Parameters:
/// - command: the command's name, not full path. eg: bash
/// - args: arg to pass to the binary, exclude argv[0] which is the path itself. eg: ["nya"]
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - stdout: a block call from pipeControlQueue in background when buffer from stdout available for read
/// - stderr: a block call from pipeControlQueue in background when buffer from stderr available for read
/// - Returns: execution recipe, see it's definition for details
@discardableResult
func shell(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
stdoutBlock: ((String) -> Void)? = nil,
stderrBlock: ((String) -> Void)? = nil
) -> ExecuteRecipe {
// the command with full file system path
var commandLocation: String?
if let location = binaryLocationFor(command: command) {
commandLocation = location
} else if !commandShouldNotExists(command: command) {
// before calling to setup, check if you telling us so
// if not so, search for the binary, for two reason:
// - table is not yet built
// - it may be added to the system after last setup
setupBinaryTable()
}
// if nil, look for the command once again, after another setup
if commandLocation == nil {
commandLocation = binaryLocationFor(command: command)
}
// make sure we find the command
guard let commandLocation = commandLocation else {
return ExecuteRecipe.failure(error: .commandNotFound)
}
// now, let's validate the command
guard isBinaryValid(at: URL(fileURLWithPath: commandLocation)) else {
return ExecuteRecipe.failure(error: .commandInvalid)
}
// finally let‘s call the spawn
let recipe = AuxiliaryExecute.spawn(
command: commandLocation,
args: args,
environment: environment,
timeout: timeout,
stdoutBlock: stdoutBlock,
stderrBlock: stderrBlock
)
return recipe
}
/// run script with bash, if bash available
/// - Parameters:
/// - command: script to be passed to bash. eg: "echo nya"
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - stdout: a block call from pipeControlQueue in background when buffer from stdout available for read
/// - stderr: a block call from pipeControlQueue in background when buffer from stderr available for read
/// - Returns: execution recipe, see it's definition for details
@discardableResult
func bash(
command: String,
environment: [String: String] = [:],
timeout: Double = 0,
stdoutBlock: ((String) -> Void)? = nil,
stderrBlock: ((String) -> Void)? = nil
) -> ExecuteRecipe {
let result = shell(
command: "bash",
args: ["-c", command],
environment: environment,
timeout: timeout,
stdoutBlock: stdoutBlock,
stderrBlock: stderrBlock
)
return result
}
}
================================================
FILE: External/AuxiliaryExecute/Sources/AuxiliaryExecute/AuxiliaryExecute+Spawn.swift
================================================
//
// AuxiliaryExecute+Spawn.swift
// AuxiliaryExecute
//
// Created by Lakr Aream on 2021/12/6.
//
import Foundation
public extension AuxiliaryExecute {
/// call posix spawn to begin execute
/// - Parameters:
/// - command: full path of the binary file. eg: "/bin/cat"
/// - args: arg to pass to the binary, exclude argv[0] which is the path itself. eg: ["nya"]
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - output: a block call from pipeControlQueue in background when buffer from stdout or stderr available for read
/// - Returns: execution recipe, see it's definition for details
@discardableResult
static func spawn(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
setPid: ((pid_t) -> Void)? = nil,
output: ((String) -> Void)? = nil
)
-> ExecuteRecipe
{
let outputLock = NSLock()
let result = spawn(
command: command,
args: args,
environment: environment,
timeout: timeout,
setPid: setPid
) { str in
outputLock.lock()
output?(str)
outputLock.unlock()
} stderrBlock: { str in
outputLock.lock()
output?(str)
outputLock.unlock()
}
return result
}
/// call posix spawn to begin execute and block until the process exits
/// - Parameters:
/// - command: full path of the binary file. eg: "/bin/cat"
/// - args: arg to pass to the binary, exclude argv[0] which is the path itself. eg: ["nya"]
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - stdout: a block call from pipeControlQueue in background when buffer from stdout available for read
/// - stderr: a block call from pipeControlQueue in background when buffer from stderr available for read
/// - Returns: execution recipe, see it's definition for details
static func spawn(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
setPid: ((pid_t) -> Void)? = nil,
stdoutBlock: ((String) -> Void)? = nil,
stderrBlock: ((String) -> Void)? = nil
) -> ExecuteRecipe {
let sema = DispatchSemaphore(value: 0)
var recipe: ExecuteRecipe!
spawn(
command: command,
args: args,
environment: environment,
timeout: timeout,
setPid: setPid,
stdoutBlock: stdoutBlock,
stderrBlock: stderrBlock
) {
recipe = $0
sema.signal()
}
sema.wait()
return recipe
}
/// call posix spawn to begin execute
/// - Parameters:
/// - command: full path of the binary file. eg: "/bin/cat"
/// - args: arg to pass to the binary, exclude argv[0] which is the path itself. eg: ["nya"]
/// - environment: any environment to be appended/overwrite when calling posix spawn. eg: ["mua" : "nya"]
/// - timeout: any wall timeout if lager than 0, in seconds. eg: 6
/// - setPid: called sync when pid available
/// - stdoutBlock: a block call from pipeControlQueue in background when buffer from stdout available for read
/// - stderrBlock: a block call from pipeControlQueue in background when buffer from stderr available for read
/// - completionBlock: a block called from processControlQueue or current queue when the process is finished or an error occurred
static func spawn(
command: String,
args: [String] = [],
environment: [String: String] = [:],
timeout: Double = 0,
setPid: ((pid_t) -> Void)? = nil,
stdoutBlock: ((String) -> Void)? = nil,
stderrBlock: ((String) -> Void)? = nil,
completionBlock: ((ExecuteRecipe) -> Void)? = nil
) {
// MARK: PREPARE FILE PIPE -
var pipestdout: [Int32] = [0, 0]
var pipestderr: [Int32] = [0, 0]
let bufsiz = Int(exactly: BUFSIZ) ?? 65535
pipe(&pipestdout)
pipe(&pipestderr)
guard fcntl(pipestdout[0], F_SETFL, O_NONBLOCK) != -1 else {
let recipe = ExecuteRecipe.failure(error: .openFilePipeFailed)
completionBlock?(recipe)
return
}
guard fcntl(pipestderr[0], F_SETFL, O_NONBLOCK) != -1 else {
let recipe = ExecuteRecipe.failure(error: .openFilePipeFailed)
completionBlock?(recipe)
return
}
// MARK: PREPARE FILE ACTION -
var fileActions: posix_spawn_file_actions_t?
posix_spawn_file_actions_init(&fileActions)
posix_spawn_file_actions_addclose(&fileActions, pipestdout[0])
posix_spawn_file_actions_addclose(&fileActions, pipestderr[0])
posix_spawn_file_actions_adddup2(&fileActions, pipestdout[1], STDOUT_FILENO)
posix_spawn_file_actions_adddup2(&fileActions, pipestderr[1], STDERR_FILENO)
posix_spawn_file_actions_addclose(&fileActions, pipestdout[1])
posix_spawn_file_actions_addclose(&fileActions, pipestderr[1])
defer {
posix_spawn_file_actions_destroy(&fileActions)
}
// MARK: PREPARE ENV -
var realEnvironmentBuilder: [String] = []
// before building the environment, we need to read from the existing environment
do {
var envBuilder = [String: String]()
var currentEnv = environ
while let rawStr = currentEnv.pointee {
defer { currentEnv += 1 }
// get the env
let str = String(cString: rawStr)
guard let key = str.components(separatedBy: "=").first else {
continue
}
if !(str.count >= "\(key)=".count) {
continue
}
// this is to aviod any problem with mua=nya=nya= that ending with =
let value = String(str.dropFirst("\(key)=".count))
envBuilder[key] = value
}
// now, let's overwrite the environment specified in parameters
for (key, value) in environment {
envBuilder[key] = value
}
// now, package those items
for (key, value) in envBuilder {
realEnvironmentBuilder.append("\(key)=\(value)")
}
}
// making it a c shit
let realEnv: [UnsafeMutablePointer?] = realEnvironmentBuilder.map { $0.withCString(strdup) }
defer { for case let env? in realEnv { free(env) } }
// MARK: PREPARE ARGS -
let args = [command] + args
let argv: [UnsafeMutablePointer?] = args.map { $0.withCString(strdup) }
defer { for case let arg? in argv { free(arg) } }
// MARK: NOW POSIX_SPAWN -
var pid: pid_t = 0
let spawnStatus = posix_spawn(&pid, command, &fileActions, nil, argv + [nil], realEnv + [nil])
if spawnStatus != 0 {
let recipe = ExecuteRecipe.failure(error: .posixSpawnFailed)
completionBlock?(recipe)
return
}
setPid?(pid)
close(pipestdout[1])
close(pipestderr[1])
var stdoutStr = ""
var stderrStr = ""
// MARK: OUTPUT BRIDGE -
let stdoutSource = DispatchSource.makeReadSource(fileDescriptor: pipestdout[0], queue: pipeControlQueue)
let stderrSource = DispatchSource.makeReadSource(fileDescriptor: pipestderr[0], queue: pipeControlQueue)
let stdoutSem = DispatchSemaphore(value: 0)
let stderrSem = DispatchSemaphore(value: 0)
stdoutSource.setCancelHandler {
close(pipestdout[0])
stdoutSem.signal()
}
stderrSource.setCancelHandler {
close(pipestderr[0])
stderrSem.signal()
}
stdoutSource.setEventHandler {
let buffer = UnsafeMutablePointer.allocate(capacity: bufsiz)
defer { buffer.deallocate() }
let bytesRead = read(pipestdout[0], buffer, bufsiz)
guard bytesRead > 0 else {
if bytesRead == -1, errno == EAGAIN {
return
}
stdoutSource.cancel()
return
}
let array = Array(UnsafeBufferPointer(start: buffer, count: bytesRead)) + [UInt8(0)]
array.withUnsafeBufferPointer { ptr in
let str = String(cString: unsafeBitCast(ptr.baseAddress, to: UnsafePointer.self))
stdoutStr += str
stdoutBlock?(str)
}
}
stderrSource.setEventHandler {
let buffer = UnsafeMutablePointer.allocate(capacity: bufsiz)
defer { buffer.deallocate() }
let bytesRead = read(pipestderr[0], buffer, bufsiz)
guard bytesRead > 0 else {
if bytesRead == -1, errno == EAGAIN {
return
}
stderrSource.cancel()
return
}
let array = Array(UnsafeBufferPointer(start: buffer, count: bytesRead)) + [UInt8(0)]
array.withUnsafeBufferPointer { ptr in
let str = String(cString: unsafeBitCast(ptr.baseAddress, to: UnsafePointer.self))
stderrStr += str
stderrBlock?(str)
}
}
stdoutSource.resume()
stderrSource.resume()
// MARK: WAIT + TIMEOUT CONTROL -
let realTimeout = timeout > 0 ? timeout : maxTimeoutValue
let wallTimeout = DispatchTime.now() + (
TimeInterval(exactly: realTimeout) ?? maxTimeoutValue
)
var status: Int32 = 0
var wait: pid_t = 0
var isTimeout = false
let timerSource = DispatchSource.makeTimerSource(flags: [], queue: processControlQueue)
timerSource.setEventHandler {
isTimeout = true
kill(pid, SIGKILL)
}
let processSource = DispatchSource.makeProcessSource(identifier: pid, eventMask: .exit, queue: processControlQueue)
processSource.setEventHandler {
wait = waitpid(pid, &status, 0)
processSource.cancel()
timerSource.cancel()
stdoutSem.wait()
stderrSem.wait()
// by using exactly method, we won't crash it!
let recipe = ExecuteRecipe(
exitCode: Int(exactly: status) ?? -1,
pid: Int(exactly: pid) ?? -1,
wait: Int(exactly: wait) ?? -1,
error: isTimeout ? .timeout : nil,
stdout: stdoutStr,
stderr: stderrStr
)
completionBlock?(recipe)
}
processSource.resume()
// timeout control
timerSource.schedule(deadline: wallTimeout)
timerSource.resume()
}
}
================================================
FILE: External/AuxiliaryExecute/Sources/AuxiliaryExecute/AuxiliaryExecute.swift
================================================
//
// AuxiliaryExecute.swift
// MyYearWithGit
//
// Created by Lakr Aream on 2021/11/27.
//
import Foundation
/// Execute command or shell with posix, shared with AuxiliaryExecute.local
public class AuxiliaryExecute {
/// we do not recommend you to subclass this singleton
public static let local = AuxiliaryExecute()
// if binary not found when you call the shell api
// we will take some time to rebuild the bianry table each time
// -->>> this is a time-heavy-task
// so use binaryLocationFor(command:) to cache it if needed
// system path
internal var currentPath: [String] = []
// system binary table
internal var binaryTable: [String: String] = [:]
// for you to put your own search path
internal var extraSearchPath: [String] = []
// for you to set your own binary table and will be used firstly
// if you set nil here
// -> we will return nil even the binary found in system path
internal var overwriteTable: [String: String?] = [:]
// this value is used when providing 0 or negative timeout paramete
internal static let maxTimeoutValue: Double = 2_147_483_647
/// when reading from file pipe, must called from async queue
internal static let pipeControlQueue = DispatchQueue(
label: "wiki.qaq.AuxiliaryExecute.pipeRead",
attributes: .concurrent
)
/// when killing process or monitoring events from process, must called from async queue
/// we are making this queue serial queue so won't called at the same time when timeout
internal static let processControlQueue = DispatchQueue(
label: "wiki.qaq.AuxiliaryExecute.processControl",
attributes: []
)
/// used for setting binary table, avoid crash
internal let lock = NSLock()
/// nope!
private init() {
// no need to setup binary table
// we will make call to it when you call the shell api
// if you only use the spawn api
// we don't need to setup the hole table cause it‘s time-heavy-task
}
/// Execution Error, do the localization your self
public enum ExecuteError: Error, LocalizedError, Codable {
// not found in path
case commandNotFound
// invalid, may be missing, wrong permission or any other reason
case commandInvalid
// fcntl failed
case openFilePipeFailed
// posix failed
case posixSpawnFailed
// waitpid failed
case waitPidFailed
// timeout when execute
case timeout
}
/// Execution Recipe
public struct ExecuteRecipe: Codable {
// exit code, usually 0 - 255 by system
// -1 means something bad happened, set by us for convince
public let exitCode: Int
// process pid that was when it is alive
// -1 means spawn failed in some situation
public let pid: Int
// wait result for final waitpid inside block at
// processSource - eventMask.exit, usually is pid
// -1 for other cases
public let wait: Int
// any error from us, not the command it self
// DOES NOT MEAN THAT THE COMMAND DONE WELL
public let error: ExecuteError?
// stdout
public let stdout: String
// stderr
public let stderr: String
/// General initialization of recipe object
/// - Parameters:
/// - exitCode: code when process exit
/// - pid: pid when process alive
/// - wait: wait result on waitpid
/// - error: error if any
/// - stdout: stdout
/// - stderr: stderr
internal init(
exitCode: Int,
pid: Int,
wait: Int,
error: AuxiliaryExecute.ExecuteError?,
stdout: String,
stderr: String
) {
self.exitCode = exitCode
self.pid = pid
self.wait = wait
self.error = error
self.stdout = stdout
self.stderr = stderr
}
/// Template for making failure recipe
/// - Parameters:
/// - exitCode: default -1
/// - pid: default -1
/// - wait: default -1
/// - error: error
/// - stdout: default empty
/// - stderr: default empty
internal static func failure(
exitCode: Int = -1,
pid: Int = -1,
wait: Int = -1,
error: AuxiliaryExecute.ExecuteError?,
stdout: String = "",
stderr: String = ""
) -> ExecuteRecipe {
.init(
exitCode: exitCode,
pid: pid,
wait: wait,
error: error,
stdout: stdout,
stderr: stderr
)
}
}
}
================================================
FILE: External/AuxiliaryExecute/Tests/AuxiliaryExecuteTests/AuxiliaryExecuteTests.swift
================================================
@testable import AuxiliaryExecute
import XCTest
final class AuxiliaryExecuteTests: XCTestCase {
func testMain() throws {
XCTAssertNotNil(Int(exactly: AuxiliaryExecute.maxTimeoutValue))
XCTAssertNotNil(Int32(exactly: AuxiliaryExecute.maxTimeoutValue))
XCTAssertNotNil(Double(exactly: AuxiliaryExecute.maxTimeoutValue))
XCTAssertNotNil(TimeInterval(exactly: AuxiliaryExecute.maxTimeoutValue))
do {
let result = AuxiliaryExecute.local.bash(command: "printf \"\nnya\n\"")
print(result)
XCTAssert(result.exitCode == 0)
XCTAssertNil(result.error)
XCTAssert(result.stdout == "\nnya\n")
XCTAssert(result.stderr == "")
}
do {
let result = AuxiliaryExecute.local.shell(
command: "bash",
args: ["-c", "echo $mua"],
environment: ["mua": "nya"],
timeout: 0
) { stdout in
print(stdout)
} stderrBlock: { stderr in
print(stderr)
}
XCTAssert(result.exitCode == 0)
XCTAssertNil(result.error)
XCTAssert(result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) == "nya")
XCTAssert(result.stderr == "")
}
do {
let result = AuxiliaryExecute.local.shell(
command: "bash",
args: ["-c", "echo $mua"],
environment: ["mua": "nya=nya="],
timeout: 0
) { stdout in
print(stdout)
} stderrBlock: { stderr in
print(stderr)
}
XCTAssert(result.exitCode == 0)
XCTAssertNil(result.error)
XCTAssert(result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) == "nya=nya=")
XCTAssert(result.stderr == "")
}
do {
let result = AuxiliaryExecute.local.shell(
command: "tail",
args: ["-f", "/dev/null"],
timeout: 1
) { stdout in
print(stdout)
} stderrBlock: { stderr in
print(stderr)
}
XCTAssert(result.exitCode == SIGKILL)
XCTAssert(result.error == .timeout)
}
}
@available(macOS 12.0.0, *)
func testAsync() async throws {
do {
let result = await AuxiliaryExecute.spawnAsync(
command: "/usr/bin/uname",
args: ["-a"],
timeout: 1
) { stdout in
print(stdout)
} stderrBlock: { stderr in
print(stderr)
}
XCTAssertEqual(result.exitCode, 0)
XCTAssert(result.stdout.contains("Darwin Kernel"))
}
do {
let result = await AuxiliaryExecute.spawnAsync(
command: "/usr/bin/tail",
args: ["-f", "/dev/null"],
timeout: 1
) { stdout in
print(stdout)
} stderrBlock: { stderr in
print(stderr)
}
XCTAssertEqual(result.exitCode, Int(SIGKILL))
XCTAssertEqual(result.error, .timeout)
}
}
}
================================================
FILE: External/Colorful/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
================================================
FILE: External/Colorful/LICENSE
================================================
MIT License
Copyright (c) 2021 Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: External/Colorful/Package.swift
================================================
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "Colorful",
platforms: [
.iOS(.v13),
.tvOS(.v13),
.macOS(.v10_15),
.watchOS(.v6)
],
products: [
.library(name: "Colorful", targets: ["Colorful"]),
],
targets: [
.target(name: "Colorful", dependencies: []),
]
)
================================================
FILE: External/Colorful/README.md
================================================
# Colorful
A SwiftUI implementation of AppleCard's animated colorful blur background.
## Preview

## Usage
```
import Colorful
var body: some View {
ColorfulView()
}
```
## Customization & Defaults
```
init(
animated: Bool = defaultAnimated,
animation: Animation = defaultAnimation,
blurRadius: CGFloat = defaultBlurRadius,
colors: [Color] = defaultColorList,
colorCount: Int = defaultColorCount
)
```
## License
Colorful is licensed under [MIT](./LICENSE).
---
Copyright © 2021 Lakr Aream. All Rights Reserved.
================================================
FILE: External/Colorful/Sources/Colorful/Colorful.swift
================================================
//
// Colorful.swift
//
//
// Created by Lakr Aream on 2021/9/19.
//
import SwiftUI
private let kDefaultSourceColorList = [#colorLiteral(red: 0.9586862922, green: 0.660125792, blue: 0.8447988033, alpha: 1), #colorLiteral(red: 0.8714533448, green: 0.723166883, blue: 0.9342088699, alpha: 1), #colorLiteral(red: 0.7458761334, green: 0.7851135731, blue: 0.9899476171, alpha: 1), #colorLiteral(red: 0.4398113191, green: 0.8953480721, blue: 0.9796616435, alpha: 1), #colorLiteral(red: 0.3484552801, green: 0.933657825, blue: 0.9058339596, alpha: 1), #colorLiteral(red: 0.5567936897, green: 0.9780793786, blue: 0.6893508434, alpha: 1)]
public extension ColorfulView {
static let defaultAnimated: Bool = true
static let defaultBlurRadius: CGFloat = 64
static let defaultColorCount: Int = 32
static let defaultAnimation: Animation = Animation
.interpolatingSpring(stiffness: 50, damping: 1)
.speed(0.05)
static let defaultColorList: [Color] = kDefaultSourceColorList
.map { Color($0) }
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
static let defaultColorListNSColor: [NSColor] = kDefaultSourceColorList
#endif
#if canImport(UIKit)
static let defaultColorListUIColor: [UIColor] = kDefaultSourceColorList
#endif
}
================================================
FILE: External/Colorful/Sources/Colorful/ColorfulView.swift
================================================
//
// ColorfulView.swift
// Colorful
//
// Created by Lakr Aream on 2021/9/19.
//
import SwiftUI
public struct ColorfulView: View {
// MARK: - PROPERTY
@State var randomization: [PointRandomization]
@State var size: CGSize = .init()
private let colorElements: [Color]
private let animated: Bool
private let animation: Animation
private let blurRadius: CGFloat
private let timer = Timer
.publish(every: 5, on: .main, in: .common)
.autoconnect()
// MARK: - INIT
public init(
animated: Bool = defaultAnimated,
animation: Animation = defaultAnimation,
blurRadius: CGFloat = defaultBlurRadius,
colors: [Color] = defaultColorList,
colorCount: Int = defaultColorCount
) {
assert(colors.count > 0)
assert(colorCount > 0)
assert(blurRadius > 0)
self.animated = animated
self.animation = animation
self.blurRadius = blurRadius
var colorCompiler = [Color]()
while colorCompiler.count < colorCount {
colorCompiler.append(contentsOf: colors.shuffled())
}
if colorCompiler.count > colorCount {
colorCompiler.removeLast(colorCompiler.count - colorCount)
}
assert(colorCompiler.count == colorCount)
colorElements = colorCompiler
var builder = [PointRandomization]()
for _ in 0 ..< colorCount {
builder.append(.init())
}
_randomization = State(initialValue: builder)
}
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
public init(
animated: Bool = defaultAnimated,
animation: Animation = defaultAnimation,
blurRadius: CGFloat = defaultBlurRadius,
nsColors: [NSColor],
colorCount: Int = defaultColorCount
) {
self.init(
animated: animated,
animation: animation,
blurRadius: blurRadius,
colors: nsColors.map { Color($0) },
colorCount: colorCount
)
}
#endif
#if canImport(UIKit)
public init(
animated: Bool = defaultAnimated,
animation: Animation = defaultAnimation,
blurRadius: CGFloat = defaultBlurRadius,
uiColors: [UIColor],
colorCount: Int = defaultColorCount
) {
self.init(
animated: animated,
animation: animation,
blurRadius: blurRadius,
colors: uiColors.map { Color($0) },
colorCount: colorCount
)
}
#endif
// MARK: - VIEW
public var body: some View {
GeometryReader { reader in
ZStack {
ForEach(obtainRangeAndUpdate(size: reader.size)) { configure in
Circle()
.foregroundColor(configure.color)
.opacity(0.5)
.frame(
width: configure.diameter,
height: configure.diameter
)
.offset(
x: configure.offsetX,
y: configure.offsetY
)
}
}
.frame(width: reader.size.width,
height: reader.size.height)
}
.clipped()
.blur(radius: blurRadius)
.onReceive(timer) { _ in
dispatchUpdate()
}
.onAppear {
randomizationStart()
}
}
// MARK: - FUNCTION
private func dispatchUpdate() {
if !animated { return }
withAnimation(animation) {
randomizationStart()
}
}
private func randomizationStart() {
var randomizationBuilder = [PointRandomization]()
for i in 0 ..< randomization.count {
let randomizationElement: PointRandomization = {
var builder = PointRandomization()
builder.randomizeIn(size: size)
builder.id = randomization[i].id
builder.color = colorElements[i]
return builder
}()
randomizationBuilder.append(randomizationElement)
}
randomization = randomizationBuilder
}
private func obtainRangeAndUpdate(size: CGSize) -> [PointRandomization] {
issueSizeUpdate(withValue: size)
return randomization
}
private func issueSizeUpdate(withValue size: CGSize) {
if self.size == size { return }
DispatchQueue.main.async {
self.size = size
self.dispatchUpdate()
}
}
}
================================================
FILE: External/Colorful/Sources/Colorful/PointRandomization.swift
================================================
//
// PointRandomization.swift
// Colorful
//
// Created by Lakr Aream on 2021/9/19.
//
import SwiftUI
extension ColorfulView {
struct PointRandomization: Equatable, Hashable, Identifiable {
var id = UUID()
var diameter: CGFloat = 0
var offsetX: CGFloat = 0
var offsetY: CGFloat = 0
var color: Color = .white.opacity(0)
mutating func randomizeIn(size: CGSize) {
let decision = (size.width + size.height) / 4
diameter = CGFloat.random(in: (decision * 0.25) ... (decision * 0.75))
offsetX = CGFloat.random(in: -(size.width / 2) ... +(size.width / 2))
offsetY = CGFloat.random(in: -(size.height / 2) ... +(size.height / 2))
}
func hash(into hasher: inout Hasher) {
hasher.combine(diameter)
hasher.combine(offsetX)
hasher.combine(offsetY)
}
static func == (lhs: PointRandomization, rhs: PointRandomization) -> Bool {
lhs.diameter == rhs.diameter &&
lhs.offsetX == rhs.offsetX &&
lhs.offsetY == rhs.offsetY
}
}
}
================================================
FILE: External/KeychainAccess/.gitignore
================================================
### https://raw.github.com/github/gitignore/2a4de265d37eca626309d8e115218d18985b5435/Swift.gitignore
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## User settings
xcuserdata/
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
## Obj-C/Swift specific
*.hmap
## App packaging
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build/
# Accio dependency management
Dependencies/
.accio/
# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/
### https://raw.github.com/github/gitignore/2a4de265d37eca626309d8e115218d18985b5435/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### https://raw.github.com/github/gitignore/2a4de265d37eca626309d8e115218d18985b5435/Ruby.gitignore
*.gem
*.rbc
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/spec/examples.txt
/test/tmp/
/test/version_tmp/
/tmp/
# Used by dotenv library to load environment variables.
# .env
# Ignore Byebug command history file.
.byebug_history
## Specific to RubyMotion:
.dat*
.repl_history
build/
*.bridgesupport
build-iPhoneOS/
build-iPhoneSimulator/
## Specific to RubyMotion (use of CocoaPods):
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# vendor/Pods/
## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/rdoc/
## Environment normalization:
/.bundle/
/vendor/bundle
/lib/bundler/man/
# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--*
================================================
FILE: External/KeychainAccess/.travis.yml
================================================
language: objective-c
cache:
directories:
- Lib/vendor
install:
- "(cd Lib && bundle install --path=vendor/bundle --binstubs=vendor/bin)"
before_script:
- ./Lib/Scripts/decode_cert.sh || true
- ./Lib/Scripts/add_key.sh || true
script:
- "(cd Lib && travis_retry bundle exec rake $ACTION)"
matrix:
include:
- osx_image: xcode11
env: ACTION=build
- osx_image: xcode11
env: ACTION='build:carthage'
- osx_image: xcode11
env: ACTION='test:iphonesimulator'
- osx_image: xcode11
env: ACTION='test:appletvsimulator'
- osx_image: xcode11
env: ACTION='test:macosx'
# Mac Catalyst requires macOS Catalina. But no CI service supports running tests on Catalina yet.
# - osx_image: xcode11
# script: xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -configuration Debug -enableCodeCoverage YES -derivedDataPath build -hideShellScriptEnvironment -destination 'platform=macOS,arch=x86_64,variant=Mac Catalyst' -only-testing:KeychainAccessTests-MacCatalyst SWIFT_VERSION=5.1 GCC_SYMBOLS_PRIVATE_EXTERN=NO
- osx_image: xcode10.3
env: ACTION=build
- osx_image: xcode10.3
env: ACTION='build:carthage'
- osx_image: xcode10.3
env: ACTION='test:iphonesimulator'
- osx_image: xcode10.3
env: ACTION='test:appletvsimulator'
- osx_image: xcode10.3
env: ACTION='test:macosx'
- osx_image: xcode10.2
env: ACTION=build
- osx_image: xcode10.2
env: ACTION='build:carthage'
- osx_image: xcode10.2
env: ACTION='test:iphonesimulator'
- osx_image: xcode10.2
env: ACTION='test:appletvsimulator'
- osx_image: xcode10.2
env: ACTION='test:macosx'
- osx_image: xcode10
env: ACTION=build
- osx_image: xcode10
env: ACTION='build:carthage'
- osx_image: xcode10
env: ACTION='test:iphonesimulator'
- osx_image: xcode10
env: ACTION='test:appletvsimulator'
- osx_image: xcode10
env: ACTION='test:macosx'
- osx_image: xcode9.4
env: ACTION=build
- osx_image: xcode9.4
env: ACTION='build:carthage'
- osx_image: xcode9.4
env: ACTION='test:iphonesimulator'
- osx_image: xcode9.4
env: ACTION='test:appletvsimulator'
- osx_image: xcode9.4
env: ACTION='test:macosx'
env:
global:
- LANG=en_US.UTF-8
- LC_ALL=en_US.UTF-8
- secure: KL59HA2XSRa215qVXXnFpx48Tb/k+vNfFAbzyc+0M4mXl1VhSJv3bkTslqDrX822t3iFDFYhXbJ6aUo7szSdcbnCXU7VIhNPRK5QM00eS1AI4V0UwDQZ06g2f4Dmt+cQxACg+0CB0OaPnUCA4rkQQKeBMAWa67Tp2hNgQHwsnio=
- secure: B8zXiyX1zEq6uWaCxap5iW1joQBoOjNjSUlcs1t+QKdaFCFtjOI8C1JCClzk7rTnGNDDrhahFlE8yskSNKoBsaW2UJ8TzPIkD4F2pkxTHkaFQl/GBsdbHdOUFL4h0/zGQ6wY1Qhw7C+8+3U+1c9QbnNw6jOQwXTF6gs/XTNzG9Y=
branches:
only:
- master
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/AccountsViewController.swift
================================================
//
// AccountsViewController.swift
// Example
//
// Created by kishikawa katsumi on 2014/12/25.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
import KeychainAccess
class AccountsViewController: UITableViewController {
var itemsGroupedByService: [String: [[String: Any]]]?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadData()
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK:
override func numberOfSections(in tableView: UITableView) -> Int {
if itemsGroupedByService != nil {
let services = Array(itemsGroupedByService!.keys)
return services.count
}
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let services = Array(itemsGroupedByService!.keys)
let service = services[section]
let items = Keychain(service: service).allItems()
return items.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let services = Array(itemsGroupedByService!.keys)
return services[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let services = Array(itemsGroupedByService!.keys)
let service = services[indexPath.section]
let items = Keychain(service: service).allItems()
let item = items[indexPath.row]
cell.textLabel?.text = item["key"] as? String
cell.detailTextLabel?.text = item["value"] as? String
return cell
}
#if swift(>=4.2)
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let services = Array(itemsGroupedByService!.keys)
let service = services[indexPath.section]
let keychain = Keychain(service: service)
let items = keychain.allItems()
let item = items[indexPath.row]
let key = item["key"] as! String
keychain[key] = nil
if items.count == 1 {
reloadData()
tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic)
} else {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
#else
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let services = Array(itemsGroupedByService!.keys)
let service = services[indexPath.section]
let keychain = Keychain(service: service)
let items = keychain.allItems()
let item = items[indexPath.row]
let key = item["key"] as! String
keychain[key] = nil
if items.count == 1 {
reloadData()
tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic)
} else {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
#endif
// MARK:
func reloadData() {
let items = Keychain.allItems(.genericPassword)
itemsGroupedByService = groupBy(items) { item -> String in
if let service = item["service"] as? String {
return service
}
return ""
}
}
}
private func groupBy(_ xs: C, key: (C.Iterator.Element) -> K) -> [K:[C.Iterator.Element]] {
var gs: [K:[C.Iterator.Element]] = [:]
for x in xs {
let k = key(x)
var ys = gs[k] ?? []
ys.append(x)
gs.updateValue(ys, forKey: k)
}
return gs
}
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/AppDelegate.swift
================================================
//
// AppDelegate.swift
// Example
//
// Created by kishikawa katsumi on 2014/12/25.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
#if swift(>=4.2)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#else
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#endif
}
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/Base.lproj/LaunchScreen.xib
================================================
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/Base.lproj/Main.storyboard
================================================
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/Example-iOS.entitlements
================================================
keychain-access-groups
$(AppIdentifierPrefix)com.kishikawakatsumi.Example-iOS
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Main
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS/InputViewController.swift
================================================
//
// InputViewController.swift
// Example
//
// Created by kishikawa katsumi on 2014/12/26.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
import KeychainAccess
class InputViewController: UITableViewController {
@IBOutlet weak var saveButton: UIBarButtonItem!
@IBOutlet weak var cancelButton: UIBarButtonItem!
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
@IBOutlet weak var serviceField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 44.0
tableView.estimatedRowHeight = 44.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK:
@IBAction func cancelAction(sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
@IBAction func saveAction(sender: UIBarButtonItem) {
let keychain: Keychain
if let service = serviceField.text, !service.isEmpty {
keychain = Keychain(service: service)
} else {
keychain = Keychain()
}
keychain[usernameField.text!] = passwordField.text
dismiss(animated: true, completion: nil)
}
@IBAction func editingChanged(sender: UITextField) {
switch (usernameField.text, passwordField.text) {
case let (username?, password?):
saveButton.isEnabled = !username.isEmpty && !password.isEmpty
case (_?, nil):
saveButton.isEnabled = false
case (nil, _?):
saveButton.isEnabled = false
case (nil, nil):
saveButton.isEnabled = false
}
}
}
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
14DAEE961A51E1BE0070B77E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEE951A51E1BE0070B77E /* AppDelegate.swift */; };
14DAEE9B1A51E1BE0070B77E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE991A51E1BE0070B77E /* Main.storyboard */; };
14DAEE9D1A51E1BE0070B77E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE9C1A51E1BE0070B77E /* Images.xcassets */; };
14DAEEA01A51E1BE0070B77E /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */; };
14DAEEB71A51E2690070B77E /* AccountsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEEB51A51E2690070B77E /* AccountsViewController.swift */; };
14DAEEB81A51E2690070B77E /* InputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEEB61A51E2690070B77E /* InputViewController.swift */; };
14DAEEC91A51E2D00070B77E /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */; };
14DAEECB1A51E2E10070B77E /* KeychainAccess.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
1470425D1D6FFA97005A4C6E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 14A630151D3293C700809B3F;
remoteInfo = TestHost;
};
14DAEEC01A51E2A60070B77E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 140F195C1A49D79400B0016A;
remoteInfo = "KeychainAccess-iOS";
};
14DAEEC21A51E2A60070B77E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 140F19671A49D79500B0016A;
remoteInfo = "KeychainAccess-iOSTests";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
14DAEECA1A51E2D70070B77E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
14DAEECB1A51E2E10070B77E /* KeychainAccess.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
145652E11D898BB9006E8D0E /* Example-iOS.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Example-iOS.entitlements"; sourceTree = ""; };
14DAEE901A51E1BE0070B77E /* Example-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
14DAEE941A51E1BE0070B77E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
14DAEE951A51E1BE0070B77E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
14DAEE9A1A51E1BE0070B77E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
14DAEE9C1A51E1BE0070B77E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
14DAEE9F1A51E1BE0070B77E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
14DAEEB51A51E2690070B77E /* AccountsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsViewController.swift; sourceTree = ""; };
14DAEEB61A51E2690070B77E /* InputViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputViewController.swift; sourceTree = ""; };
14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KeychainAccess.xcodeproj; path = ../../Lib/KeychainAccess.xcodeproj; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
14DAEE8D1A51E1BE0070B77E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14DAEEC91A51E2D00070B77E /* KeychainAccess.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
14DAEE871A51E1BE0070B77E = {
isa = PBXGroup;
children = (
14DAEE921A51E1BE0070B77E /* Example-iOS */,
14DAEE911A51E1BE0070B77E /* Products */,
14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */,
);
sourceTree = "";
};
14DAEE911A51E1BE0070B77E /* Products */ = {
isa = PBXGroup;
children = (
14DAEE901A51E1BE0070B77E /* Example-iOS.app */,
);
name = Products;
sourceTree = "";
};
14DAEE921A51E1BE0070B77E /* Example-iOS */ = {
isa = PBXGroup;
children = (
14DAEE951A51E1BE0070B77E /* AppDelegate.swift */,
14DAEEB51A51E2690070B77E /* AccountsViewController.swift */,
14DAEEB61A51E2690070B77E /* InputViewController.swift */,
14DAEE991A51E1BE0070B77E /* Main.storyboard */,
14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */,
14DAEE9C1A51E1BE0070B77E /* Images.xcassets */,
14DAEE931A51E1BE0070B77E /* Supporting Files */,
);
path = "Example-iOS";
sourceTree = "";
};
14DAEE931A51E1BE0070B77E /* Supporting Files */ = {
isa = PBXGroup;
children = (
14DAEE941A51E1BE0070B77E /* Info.plist */,
145652E11D898BB9006E8D0E /* Example-iOS.entitlements */,
);
name = "Supporting Files";
sourceTree = "";
};
14DAEEBA1A51E2A60070B77E /* Products */ = {
isa = PBXGroup;
children = (
14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */,
14DAEEC31A51E2A60070B77E /* KeychainAccessTests.xctest */,
1470425E1D6FFA97005A4C6E /* TestHost.app */,
);
name = Products;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
14DAEE8F1A51E1BE0070B77E /* Example-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14DAEEAF1A51E1BE0070B77E /* Build configuration list for PBXNativeTarget "Example-iOS" */;
buildPhases = (
14DAEE8C1A51E1BE0070B77E /* Sources */,
14DAEE8D1A51E1BE0070B77E /* Frameworks */,
14DAEE8E1A51E1BE0070B77E /* Resources */,
14DAEECA1A51E2D70070B77E /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "Example-iOS";
productName = "Example-iOS";
productReference = 14DAEE901A51E1BE0070B77E /* Example-iOS.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
14DAEE881A51E1BE0070B77E /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = "kishikawa katsumi";
TargetAttributes = {
14DAEE8F1A51E1BE0070B77E = {
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 14DAEE8B1A51E1BE0070B77E /* Build configuration list for PBXProject "Example-iOS" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 14DAEE871A51E1BE0070B77E;
productRefGroup = 14DAEE911A51E1BE0070B77E /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 14DAEEBA1A51E2A60070B77E /* Products */;
ProjectRef = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
},
);
projectRoot = "";
targets = (
14DAEE8F1A51E1BE0070B77E /* Example-iOS */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
1470425E1D6FFA97005A4C6E /* TestHost.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = TestHost.app;
remoteRef = 1470425D1D6FFA97005A4C6E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = KeychainAccess.framework;
remoteRef = 14DAEEC01A51E2A60070B77E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
14DAEEC31A51E2A60070B77E /* KeychainAccessTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = KeychainAccessTests.xctest;
remoteRef = 14DAEEC21A51E2A60070B77E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
14DAEE8E1A51E1BE0070B77E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14DAEE9B1A51E1BE0070B77E /* Main.storyboard in Resources */,
14DAEEA01A51E1BE0070B77E /* LaunchScreen.xib in Resources */,
14DAEE9D1A51E1BE0070B77E /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
14DAEE8C1A51E1BE0070B77E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14DAEEB81A51E2690070B77E /* InputViewController.swift in Sources */,
14DAEEB71A51E2690070B77E /* AccountsViewController.swift in Sources */,
14DAEE961A51E1BE0070B77E /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
14DAEE991A51E1BE0070B77E /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
14DAEE9A1A51E1BE0070B77E /* Base */,
);
name = Main.storyboard;
sourceTree = "";
};
14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
14DAEE9F1A51E1BE0070B77E /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
14DAEEAD1A51E1BE0070B77E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "Example-iOS/Example-iOS.entitlements";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
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;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.1;
};
name = Debug;
};
14DAEEAE1A51E1BE0070B77E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "Example-iOS/Example-iOS.entitlements";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
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;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.1;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
14DAEEB01A51E1BE0070B77E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "Example-iOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
14DAEEB11A51E1BE0070B77E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "Example-iOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
14DAEE8B1A51E1BE0070B77E /* Build configuration list for PBXProject "Example-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14DAEEAD1A51E1BE0070B77E /* Debug */,
14DAEEAE1A51E1BE0070B77E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
14DAEEAF1A51E1BE0070B77E /* Build configuration list for PBXNativeTarget "Example-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14DAEEB01A51E1BE0070B77E /* Debug */,
14DAEEB11A51E1BE0070B77E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 14DAEE881A51E1BE0070B77E /* Project object */;
}
================================================
FILE: External/KeychainAccess/Examples/Example-iOS/Example-iOS.xcodeproj/xcshareddata/xcschemes/Example-iOS.xcscheme
================================================
================================================
FILE: External/KeychainAccess/KeychainAccess.podspec
================================================
Pod::Spec.new do |s|
s.name = 'KeychainAccess'
s.version = '4.2.2'
s.summary = 'KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X.'
s.description = <<-DESC
KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X.
Makes using Keychain APIs exremely easy and much more palatable to use in Swift.
Features
- Simple interface
- Support access group
- Support accessibility
- Support iCloud sharing
- **Support TouchID and Keychain integration (iOS 8+)**
- **Support Shared Web Credentials (iOS 8+)**
- Works on both iOS & OS X
- watchOS and tvOS are also supported
DESC
s.homepage = 'https://github.com/kishikawakatsumi/KeychainAccess'
s.screenshots = 'https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/01.png'
s.license = 'MIT'
s.author = { 'kishikawa katsumi' => 'kishikawakatsumi@mac.com' }
s.source = { :git => 'https://github.com/kishikawakatsumi/KeychainAccess.git', :tag => "v#{s.version}" }
s.social_media_url = 'https://twitter.com/k_katsumi'
s.requires_arc = true
s.source_files = 'Lib/KeychainAccess/*.swift'
s.swift_version = '5.1'
s.ios.deployment_target = '9.0'
s.osx.deployment_target = '10.9'
s.watchos.deployment_target = '3.0'
s.tvos.deployment_target = '9.0'
end
================================================
FILE: External/KeychainAccess/KeychainAccess.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: External/KeychainAccess/KeychainAccess.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: External/KeychainAccess/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 kishikawa katsumi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: External/KeychainAccess/Lib/Certificates/KeychainAccess_Tests.provisionprofile.enc
================================================
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
m1nn1kcLs46WQmS7a7XSHQ==
================================================
FILE: External/KeychainAccess/Lib/Certificates/developer_id_app.p12.enc
================================================
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
================================================
FILE: External/KeychainAccess/Lib/Certificates/iOS_Development.mobileprovision.enc
================================================
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
================================================
FILE: External/KeychainAccess/Lib/Certificates/ios_developer.p12.enc
================================================
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
hfJJH1uvIO2vkPfr+fxvTQ==
================================================
FILE: External/KeychainAccess/Lib/Certificates/tvOS_Development.mobileprovision.enc
================================================
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
================================================
FILE: External/KeychainAccess/Lib/Configurations/Base.xcconfig
================================================
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES
CLANG_CXX_LANGUAGE_STANDARD = gnu++0x;
CLANG_CXX_LIBRARY = libc++;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_DYNAMIC_NO_PIC = NO;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
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;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
CODE_SIGN_IDENTITY = ;
DEVELOPMENT_TEAM = ;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
WATCHOS_DEPLOYMENT_TARGET = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
SWIFT_VERSION = 5.0;
================================================
FILE: External/KeychainAccess/Lib/Configurations/Debug.xcconfig
================================================
#include "Base.xcconfig"
BITCODE_GENERATION_MODE = marker;
MTL_ENABLE_DEBUG_INFO = YES;
COPY_PHASE_STRIP = NO;
ENABLE_TESTABILITY = YES;
GCC_OPTIMIZATION_LEVEL = 0;
ONLY_ACTIVE_ARCH = YES;
SWIFT_OPTIMIZATION_LEVEL = -Onone;
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1;
================================================
FILE: External/KeychainAccess/Lib/Configurations/KeychainAccess.xcconfig
================================================
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator;
TARGETED_DEVICE_FAMILY = 1,2,3,4;
SUPPORTS_MACCATALYST = YES;
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
COMBINE_HIDPI_IMAGES = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.$(PLATFORM_NAME).$(PRODUCT_NAME:rfc1034identifier);
PRODUCT_NAME = $(PROJECT_NAME);
APPLICATION_EXTENSION_API_ONLY = YES;
INFOPLIST_FILE = KeychainAccess/Info.plist;
SKIP_INSTALL = YES;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = @rpath;
ENABLE_BITCODE[sdk=iphone*] = YES;
ENABLE_BITCODE[sdk=watch*] = YES;
ENABLE_BITCODE[sdk=appletv*] = YES;
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks;
================================================
FILE: External/KeychainAccess/Lib/Configurations/Release.xcconfig
================================================
#include "Base.xcconfig"
BITCODE_GENERATION_MODE = bitcode;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
MTL_ENABLE_DEBUG_INFO = NO;
VALIDATE_PRODUCT = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = -Owholemodule;
================================================
FILE: External/KeychainAccess/Lib/Configurations/TestHost.xcconfig
================================================
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator;
TARGETED_DEVICE_FAMILY = 1,2,3;
SUPPORTS_MACCATALYST = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = TestHost/Info.plist;
PRODUCT_NAME = $(TARGET_NAME);
CLANG_MODULES_AUTOLINK = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.KeychainAccess.TestHost;
CODE_SIGN_ENTITLEMENTS = TestHost/TestHost.entitlements;
CODE_SIGN_IDENTITY[sdk=iphone*] = iPhone Developer;
CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application;
PROVISIONING_PROFILE_SPECIFIER[sdk=iphone*] = iOS Development;
PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = KeychainAccess Tests;
DEVELOPMENT_TEAM = 27AEDK3C9F;
PRINCIPAL_CLASS[sdk=iphone*] = UIApplication;
PRINCIPAL_CLASS[sdk=appletv*] = UIApplication;
PRINCIPAL_CLASS[sdk=macosx*] = NSApplication;
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks;
================================================
FILE: External/KeychainAccess/Lib/Configurations/Tests.xcconfig
================================================
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator;
TARGETED_DEVICE_FAMILY = 1,2;
SUPPORTS_MACCATALYST = YES;
COMBINE_HIDPI_IMAGES = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier);
PRODUCT_NAME = $(TARGET_NAME);
APPLICATION_EXTENSION_API_ONLY = NO;
INFOPLIST_FILE = KeychainAccessTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks;
TEST_HOST[sdk=iphone*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost;
TEST_HOST[sdk=appletv*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost;
TEST_HOST[sdk=macosx*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/Contents/MacOS/TestHost;
EXCLUDED_SOURCE_FILE_NAMES[sdk=watch*] = *;
EXCLUDED_SOURCE_FILE_NAMES[sdk=appletv*] = SharedCredentialTests.swift;
EXCLUDED_SOURCE_FILE_NAMES[sdk=macosx*] = SharedCredentialTests.swift;
DEVELOPMENT_TEAM = 27AEDK3C9F;
================================================
FILE: External/KeychainAccess/Lib/Gemfile
================================================
source 'https://rubygems.org'
gem 'rake'
gem 'xcpretty'
gem 'xcjobs'
================================================
FILE: External/KeychainAccess/Lib/KeychainAccess/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
FMWK
CFBundleShortVersionString
4.2.2
CFBundleSignature
????
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
================================================
FILE: External/KeychainAccess/Lib/KeychainAccess/Keychain.swift
================================================
//
// Keychain.swift
// KeychainAccess
//
// Created by kishikawa katsumi on 2014/12/24.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import Security
#if os(iOS) || os(OSX)
import LocalAuthentication
#endif
public let KeychainAccessErrorDomain = "com.kishikawakatsumi.KeychainAccess.error"
public enum ItemClass {
case genericPassword
case internetPassword
}
public enum ProtocolType {
case ftp
case ftpAccount
case http
case irc
case nntp
case pop3
case smtp
case socks
case imap
case ldap
case appleTalk
case afp
case telnet
case ssh
case ftps
case https
case httpProxy
case httpsProxy
case ftpProxy
case smb
case rtsp
case rtspProxy
case daap
case eppc
case ipp
case nntps
case ldaps
case telnetS
case imaps
case ircs
case pop3S
}
public enum AuthenticationType {
case ntlm
case msn
case dpa
case rpa
case httpBasic
case httpDigest
case htmlForm
case `default`
}
public enum Accessibility {
/**
Item data can only be accessed
while the device is unlocked. This is recommended for items that only
need be accesible while the application is in the foreground. Items
with this attribute will migrate to a new device when using encrypted
backups.
*/
case whenUnlocked
/**
Item data can only be
accessed once the device has been unlocked after a restart. This is
recommended for items that need to be accesible by background
applications. Items with this attribute will migrate to a new device
when using encrypted backups.
*/
case afterFirstUnlock
/**
Item data can always be accessed
regardless of the lock state of the device. This is not recommended
for anything except system use. Items with this attribute will migrate
to a new device when using encrypted backups.
*/
@available(macCatalyst, unavailable)
case always
/**
Item data can
only be accessed while the device is unlocked. This class is only
available if a passcode is set on the device. This is recommended for
items that only need to be accessible while the application is in the
foreground. Items with this attribute will never migrate to a new
device, so after a backup is restored to a new device, these items
will be missing. No items can be stored in this class on devices
without a passcode. Disabling the device passcode will cause all
items in this class to be deleted.
*/
@available(iOS 8.0, OSX 10.10, *)
case whenPasscodeSetThisDeviceOnly
/**
Item data can only
be accessed while the device is unlocked. This is recommended for items
that only need be accesible while the application is in the foreground.
Items with this attribute will never migrate to a new device, so after
a backup is restored to a new device, these items will be missing.
*/
case whenUnlockedThisDeviceOnly
/**
Item data can
only be accessed once the device has been unlocked after a restart.
This is recommended for items that need to be accessible by background
applications. Items with this attribute will never migrate to a new
device, so after a backup is restored to a new device these items will
be missing.
*/
case afterFirstUnlockThisDeviceOnly
/**
Item data can always
be accessed regardless of the lock state of the device. This option
is not recommended for anything except system use. Items with this
attribute will never migrate to a new device, so after a backup is
restored to a new device, these items will be missing.
*/
@available(macCatalyst, unavailable)
case alwaysThisDeviceOnly
}
/**
Predefined item attribute constants used to get or set values
in a dictionary. The kSecUseAuthenticationUI constant is the key and its
value is one of the constants defined here.
If the key kSecUseAuthenticationUI not provided then kSecUseAuthenticationUIAllow
is used as default.
*/
public enum AuthenticationUI {
/**
Specifies that authenticate UI can appear.
*/
case allow
/**
Specifies that the error
errSecInteractionNotAllowed will be returned if an item needs
to authenticate with UI
*/
case fail
/**
Specifies that all items which need
to authenticate with UI will be silently skipped. This value can be used
only with SecItemCopyMatching.
*/
case skip
}
@available(iOS 9.0, OSX 10.11, *)
extension AuthenticationUI {
public var rawValue: String {
switch self {
case .allow:
return UseAuthenticationUIAllow
case .fail:
return UseAuthenticationUIFail
case .skip:
return UseAuthenticationUISkip
}
}
public var description: String {
switch self {
case .allow:
return "allow"
case .fail:
return "fail"
case .skip:
return "skip"
}
}
}
public struct AuthenticationPolicy: OptionSet {
/**
User presence policy using Touch ID or Passcode. Touch ID does not
have to be available or enrolled. Item is still accessible by Touch ID
even if fingers are added or removed.
*/
@available(iOS 8.0, OSX 10.10, watchOS 2.0, tvOS 8.0, *)
public static let userPresence = AuthenticationPolicy(rawValue: 1 << 0)
/**
Constraint: Touch ID (any finger) or Face ID. Touch ID or Face ID must be available. With Touch ID
at least one finger must be enrolled. With Face ID user has to be enrolled. Item is still accessible by Touch ID even
if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled.
*/
@available(iOS 11.3, OSX 10.13.4, watchOS 4.3, tvOS 11.3, *)
public static let biometryAny = AuthenticationPolicy(rawValue: 1 << 1)
/**
Deprecated, please use biometryAny instead.
*/
@available(iOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryAny")
@available(OSX, introduced: 10.12.1, deprecated: 10.13.4, renamed: "biometryAny")
@available(watchOS, introduced: 2.0, deprecated: 4.3, renamed: "biometryAny")
@available(tvOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryAny")
public static let touchIDAny = AuthenticationPolicy(rawValue: 1 << 1)
/**
Constraint: Touch ID from the set of currently enrolled fingers. Touch ID must be available and at least one finger must
be enrolled. When fingers are added or removed, the item is invalidated. When Face ID is re-enrolled this item is invalidated.
*/
@available(iOS 11.3, OSX 10.13, watchOS 4.3, tvOS 11.3, *)
public static let biometryCurrentSet = AuthenticationPolicy(rawValue: 1 << 3)
/**
Deprecated, please use biometryCurrentSet instead.
*/
@available(iOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryCurrentSet")
@available(OSX, introduced: 10.12.1, deprecated: 10.13.4, renamed: "biometryCurrentSet")
@available(watchOS, introduced: 2.0, deprecated: 4.3, renamed: "biometryCurrentSet")
@available(tvOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryCurrentSet")
public static let touchIDCurrentSet = AuthenticationPolicy(rawValue: 1 << 3)
/**
Constraint: Device passcode
*/
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
public static let devicePasscode = AuthenticationPolicy(rawValue: 1 << 4)
/**
Constraint: Watch
*/
@available(iOS, unavailable)
@available(OSX 10.15, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
public static let watch = AuthenticationPolicy(rawValue: 1 << 5)
/**
Constraint logic operation: when using more than one constraint,
at least one of them must be satisfied.
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let or = AuthenticationPolicy(rawValue: 1 << 14)
/**
Constraint logic operation: when using more than one constraint,
all must be satisfied.
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let and = AuthenticationPolicy(rawValue: 1 << 15)
/**
Create access control for private key operations (i.e. sign operation)
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let privateKeyUsage = AuthenticationPolicy(rawValue: 1 << 30)
/**
Security: Application provided password for data encryption key generation.
This is not a constraint but additional item encryption mechanism.
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let applicationPassword = AuthenticationPolicy(rawValue: 1 << 31)
#if swift(>=2.3)
public let rawValue: UInt
public init(rawValue: UInt) {
self.rawValue = rawValue
}
#else
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
#endif
}
public struct Attributes {
public var `class`: String? {
return attributes[Class] as? String
}
public var data: Data? {
return attributes[ValueData] as? Data
}
public var ref: Data? {
return attributes[ValueRef] as? Data
}
public var persistentRef: Data? {
return attributes[ValuePersistentRef] as? Data
}
public var accessible: String? {
return attributes[AttributeAccessible] as? String
}
public var accessControl: SecAccessControl? {
if #available(OSX 10.10, *) {
if let accessControl = attributes[AttributeAccessControl] {
return (accessControl as! SecAccessControl)
}
return nil
} else {
return nil
}
}
public var accessGroup: String? {
return attributes[AttributeAccessGroup] as? String
}
public var synchronizable: Bool? {
return attributes[AttributeSynchronizable] as? Bool
}
public var creationDate: Date? {
return attributes[AttributeCreationDate] as? Date
}
public var modificationDate: Date? {
return attributes[AttributeModificationDate] as? Date
}
public var attributeDescription: String? {
return attributes[AttributeDescription] as? String
}
public var comment: String? {
return attributes[AttributeComment] as? String
}
public var creator: String? {
return attributes[AttributeCreator] as? String
}
public var type: String? {
return attributes[AttributeType] as? String
}
public var label: String? {
return attributes[AttributeLabel] as? String
}
public var isInvisible: Bool? {
return attributes[AttributeIsInvisible] as? Bool
}
public var isNegative: Bool? {
return attributes[AttributeIsNegative] as? Bool
}
public var account: String? {
return attributes[AttributeAccount] as? String
}
public var service: String? {
return attributes[AttributeService] as? String
}
public var generic: Data? {
return attributes[AttributeGeneric] as? Data
}
public var securityDomain: String? {
return attributes[AttributeSecurityDomain] as? String
}
public var server: String? {
return attributes[AttributeServer] as? String
}
public var `protocol`: String? {
return attributes[AttributeProtocol] as? String
}
public var authenticationType: String? {
return attributes[AttributeAuthenticationType] as? String
}
public var port: Int? {
return attributes[AttributePort] as? Int
}
public var path: String? {
return attributes[AttributePath] as? String
}
fileprivate let attributes: [String: Any]
init(attributes: [String: Any]) {
self.attributes = attributes
}
public subscript(key: String) -> Any? {
get {
return attributes[key]
}
}
}
public final class Keychain {
public var itemClass: ItemClass {
return options.itemClass
}
public var service: String {
return options.service
}
// This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
// kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
public var accessGroup: String? {
return options.accessGroup
}
public var server: URL {
return options.server
}
public var protocolType: ProtocolType {
return options.protocolType
}
public var authenticationType: AuthenticationType {
return options.authenticationType
}
public var accessibility: Accessibility {
return options.accessibility
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public var authenticationPolicy: AuthenticationPolicy? {
return options.authenticationPolicy
}
public var synchronizable: Bool {
return options.synchronizable
}
public var label: String? {
return options.label
}
public var comment: String? {
return options.comment
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public var authenticationPrompt: String? {
return options.authenticationPrompt
}
@available(iOS 9.0, OSX 10.11, *)
public var authenticationUI: AuthenticationUI {
return options.authenticationUI ?? .allow
}
#if os(iOS) || os(OSX)
@available(iOS 9.0, OSX 10.11, *)
public var authenticationContext: LAContext? {
return options.authenticationContext as? LAContext
}
#endif
fileprivate let options: Options
// MARK:
public convenience init() {
var options = Options()
if let bundleIdentifier = Bundle.main.bundleIdentifier {
options.service = bundleIdentifier
}
self.init(options)
}
public convenience init(service: String) {
var options = Options()
options.service = service
self.init(options)
}
public convenience init(accessGroup: String) {
var options = Options()
if let bundleIdentifier = Bundle.main.bundleIdentifier {
options.service = bundleIdentifier
}
options.accessGroup = accessGroup
self.init(options)
}
public convenience init(service: String, accessGroup: String) {
var options = Options()
options.service = service
options.accessGroup = accessGroup
self.init(options)
}
public convenience init(server: String, protocolType: ProtocolType, accessGroup: String? = nil, authenticationType: AuthenticationType = .default) {
self.init(server: URL(string: server)!, protocolType: protocolType, accessGroup: accessGroup, authenticationType: authenticationType)
}
public convenience init(server: URL, protocolType: ProtocolType, accessGroup: String? = nil, authenticationType: AuthenticationType = .default) {
var options = Options()
options.itemClass = .internetPassword
options.server = server
options.protocolType = protocolType
options.accessGroup = accessGroup
options.authenticationType = authenticationType
self.init(options)
}
fileprivate init(_ opts: Options) {
options = opts
}
// MARK:
public func accessibility(_ accessibility: Accessibility) -> Keychain {
var options = self.options
options.accessibility = accessibility
return Keychain(options)
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public func accessibility(_ accessibility: Accessibility, authenticationPolicy: AuthenticationPolicy) -> Keychain {
var options = self.options
options.accessibility = accessibility
options.authenticationPolicy = authenticationPolicy
return Keychain(options)
}
public func synchronizable(_ synchronizable: Bool) -> Keychain {
var options = self.options
options.synchronizable = synchronizable
return Keychain(options)
}
public func label(_ label: String) -> Keychain {
var options = self.options
options.label = label
return Keychain(options)
}
public func comment(_ comment: String) -> Keychain {
var options = self.options
options.comment = comment
return Keychain(options)
}
public func attributes(_ attributes: [String: Any]) -> Keychain {
var options = self.options
attributes.forEach { options.attributes.updateValue($1, forKey: $0) }
return Keychain(options)
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public func authenticationPrompt(_ authenticationPrompt: String) -> Keychain {
var options = self.options
options.authenticationPrompt = authenticationPrompt
return Keychain(options)
}
@available(iOS 9.0, OSX 10.11, *)
public func authenticationUI(_ authenticationUI: AuthenticationUI) -> Keychain {
var options = self.options
options.authenticationUI = authenticationUI
return Keychain(options)
}
#if os(iOS) || os(OSX)
@available(iOS 9.0, OSX 10.11, *)
public func authenticationContext(_ authenticationContext: LAContext) -> Keychain {
var options = self.options
options.authenticationContext = authenticationContext
return Keychain(options)
}
#endif
// MARK:
public func get(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
return try getString(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}
public func getString(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
guard let data = try getData(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable) else {
return nil
}
guard let string = String(data: data, encoding: .utf8) else {
print("failed to convert data to string")
throw Status.conversionError
}
return string
}
public func getData(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> Data? {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[MatchLimit] = MatchLimitOne
query[ReturnData] = kCFBooleanTrue
query[AttributeAccount] = key
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
guard let data = result as? Data else {
throw Status.unexpectedError
}
return data
case errSecItemNotFound:
return nil
default:
throw securityError(status: status)
}
}
public func get(_ key: String, ignoringAttributeSynchronizable: Bool = true, handler: (Attributes?) -> T) throws -> T {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[MatchLimit] = MatchLimitOne
query[ReturnData] = kCFBooleanTrue
query[ReturnAttributes] = kCFBooleanTrue
query[ReturnRef] = kCFBooleanTrue
query[ReturnPersistentRef] = kCFBooleanTrue
query[AttributeAccount] = key
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
guard let attributes = result as? [String: Any] else {
throw Status.unexpectedError
}
return handler(Attributes(attributes: attributes))
case errSecItemNotFound:
return handler(nil)
default:
throw securityError(status: status)
}
}
// MARK:
public func set(_ value: String, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
guard let data = value.data(using: .utf8, allowLossyConversion: false) else {
print("failed to convert string to data")
throw Status.conversionError
}
try set(data, key: key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}
public func set(_ value: Data, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[AttributeAccount] = key
#if os(iOS)
if #available(iOS 9.0, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
} else {
query[UseNoAuthenticationUI] = kCFBooleanTrue
}
#elseif os(OSX)
query[ReturnData] = kCFBooleanTrue
if #available(OSX 10.11, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
}
#else
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
}
#endif
var status = SecItemCopyMatching(query as CFDictionary, nil)
switch status {
case errSecSuccess, errSecInteractionNotAllowed:
var query = options.query()
query[AttributeAccount] = key
var (attributes, error) = options.attributes(key: nil, value: value)
if let error = error {
print(error.localizedDescription)
throw error
}
options.attributes.forEach { attributes.updateValue($1, forKey: $0) }
#if os(iOS)
if status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_8_0) {
try remove(key)
try set(value, key: key)
} else {
status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
if status != errSecSuccess {
throw securityError(status: status)
}
}
#else
status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
if status != errSecSuccess {
throw securityError(status: status)
}
#endif
case errSecItemNotFound:
var (attributes, error) = options.attributes(key: key, value: value)
if let error = error {
print(error.localizedDescription)
throw error
}
options.attributes.forEach { attributes.updateValue($1, forKey: $0) }
status = SecItemAdd(attributes as CFDictionary, nil)
if status != errSecSuccess {
throw securityError(status: status)
}
default:
throw securityError(status: status)
}
}
public subscript(key: String) -> String? {
get {
#if swift(>=5.0)
return try? get(key)
#else
return (try? get(key)).flatMap { $0 }
#endif
}
set {
if let value = newValue {
do {
try set(value, key: key)
} catch {}
} else {
do {
try remove(key)
} catch {}
}
}
}
public subscript(string key: String) -> String? {
get {
return self[key]
}
set {
self[key] = newValue
}
}
public subscript(data key: String) -> Data? {
get {
#if swift(>=5.0)
return try? getData(key)
#else
return (try? getData(key)).flatMap { $0 }
#endif
}
set {
if let value = newValue {
do {
try set(value, key: key)
} catch {}
} else {
do {
try remove(key)
} catch {}
}
}
}
public subscript(attributes key: String) -> Attributes? {
get {
#if swift(>=5.0)
return try? get(key) { $0 }
#else
return (try? get(key) { $0 }).flatMap { $0 }
#endif
}
}
// MARK:
public func remove(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[AttributeAccount] = key
let status = SecItemDelete(query as CFDictionary)
if status != errSecSuccess && status != errSecItemNotFound {
throw securityError(status: status)
}
}
public func removeAll() throws {
var query = options.query()
#if !os(iOS) && !os(watchOS) && !os(tvOS)
query[MatchLimit] = MatchLimitAll
#endif
let status = SecItemDelete(query as CFDictionary)
if status != errSecSuccess && status != errSecItemNotFound {
throw securityError(status: status)
}
}
// MARK:
public func contains(_ key: String, withoutAuthenticationUI: Bool = false) throws -> Bool {
var query = options.query()
query[AttributeAccount] = key
if withoutAuthenticationUI {
#if os(iOS) || os(watchOS) || os(tvOS)
if #available(iOS 9.0, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
} else {
query[UseNoAuthenticationUI] = kCFBooleanTrue
}
#else
if #available(OSX 10.11, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
} else if #available(OSX 10.10, *) {
query[UseNoAuthenticationUI] = kCFBooleanTrue
}
#endif
} else {
if #available(iOS 9.0, OSX 10.11, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
}
}
}
let status = SecItemCopyMatching(query as CFDictionary, nil)
switch status {
case errSecSuccess:
return true
case errSecInteractionNotAllowed:
if withoutAuthenticationUI {
return true
}
return false
case errSecItemNotFound:
return false
default:
throw securityError(status: status)
}
}
// MARK:
public class func allKeys(_ itemClass: ItemClass) -> [(String, String)] {
var query = [String: Any]()
query[Class] = itemClass.rawValue
query[AttributeSynchronizable] = SynchronizableAny
query[MatchLimit] = MatchLimitAll
query[ReturnAttributes] = kCFBooleanTrue
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
if let items = result as? [[String: Any]] {
return prettify(itemClass: itemClass, items: items).map {
switch itemClass {
case .genericPassword:
return (($0["service"] ?? "") as! String, ($0["key"] ?? "") as! String)
case .internetPassword:
return (($0["server"] ?? "") as! String, ($0["key"] ?? "") as! String)
}
}
}
case errSecItemNotFound:
return []
default: ()
}
securityError(status: status)
return []
}
public func allKeys() -> [String] {
let allItems = type(of: self).prettify(itemClass: itemClass, items: items())
let filter: ([String: Any]) -> String? = { $0["key"] as? String }
#if swift(>=4.1)
return allItems.compactMap(filter)
#else
return allItems.flatMap(filter)
#endif
}
public class func allItems(_ itemClass: ItemClass) -> [[String: Any]] {
var query = [String: Any]()
query[Class] = itemClass.rawValue
query[MatchLimit] = MatchLimitAll
query[ReturnAttributes] = kCFBooleanTrue
#if os(iOS) || os(watchOS) || os(tvOS)
query[ReturnData] = kCFBooleanTrue
#endif
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
if let items = result as? [[String: Any]] {
return prettify(itemClass: itemClass, items: items)
}
case errSecItemNotFound:
return []
default: ()
}
securityError(status: status)
return []
}
public func allItems() -> [[String: Any]] {
return type(of: self).prettify(itemClass: itemClass, items: items())
}
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func getSharedPassword(_ completion: @escaping (_ account: String?, _ password: String?, _ error: Error?) -> () = { account, password, error -> () in }) {
if let domain = server.host {
type(of: self).requestSharedWebCredential(domain: domain, account: nil) { (credentials, error) -> () in
if let credential = credentials.first {
let account = credential["account"]
let password = credential["password"]
completion(account, password, error)
} else {
completion(nil, nil, error)
}
}
} else {
let error = securityError(status: Status.param.rawValue)
completion(nil, nil, error)
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func getSharedPassword(_ account: String, completion: @escaping (_ password: String?, _ error: Error?) -> () = { password, error -> () in }) {
if let domain = server.host {
type(of: self).requestSharedWebCredential(domain: domain, account: account) { (credentials, error) -> () in
if let credential = credentials.first {
if let password = credential["password"] {
completion(password, error)
} else {
completion(nil, error)
}
} else {
completion(nil, error)
}
}
} else {
let error = securityError(status: Status.param.rawValue)
completion(nil, error)
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func setSharedPassword(_ password: String, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
setSharedPassword(password as String?, account: account, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
fileprivate func setSharedPassword(_ password: String?, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
if let domain = server.host {
SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { error -> () in
if let error = error {
completion(error.error)
} else {
completion(nil)
}
}
} else {
let error = securityError(status: Status.param.rawValue)
completion(error)
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func removeSharedPassword(_ account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
setSharedPassword(nil, account: account, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public class func requestSharedWebCredential(_ completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
requestSharedWebCredential(domain: nil, account: nil, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public class func requestSharedWebCredential(domain: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
requestSharedWebCredential(domain: domain, account: nil, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public class func requestSharedWebCredential(domain: String, account: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
requestSharedWebCredential(domain: Optional(domain), account: Optional(account)!, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
fileprivate class func requestSharedWebCredential(domain: String?, account: String?, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> ()) {
SecRequestSharedWebCredential(domain as CFString?, account as CFString?) { (credentials, error) -> () in
var remoteError: NSError?
if let error = error {
remoteError = error.error
if remoteError?.code != Int(errSecItemNotFound) {
print("error:[\(remoteError!.code)] \(remoteError!.localizedDescription)")
}
}
if let credentials = credentials {
let credentials = (credentials as NSArray).map { credentials -> [String: String] in
var credential = [String: String]()
if let credentials = credentials as? [String: String] {
if let server = credentials[AttributeServer] {
credential["server"] = server
}
if let account = credentials[AttributeAccount] {
credential["account"] = account
}
if let password = credentials[SharedPassword] {
credential["password"] = password
}
}
return credential
}
completion(credentials, remoteError)
} else {
completion([], remoteError)
}
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
/**
@abstract Returns a randomly generated password.
@return String password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present.
*/
@available(iOS 8.0, *)
public class func generatePassword() -> String {
return SecCreateSharedWebCredentialPassword()! as String
}
#endif
// MARK:
fileprivate func items() -> [[String: Any]] {
var query = options.query()
query[MatchLimit] = MatchLimitAll
query[ReturnAttributes] = kCFBooleanTrue
#if os(iOS) || os(watchOS) || os(tvOS)
query[ReturnData] = kCFBooleanTrue
#endif
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
if let items = result as? [[String: Any]] {
return items
}
case errSecItemNotFound:
return []
default: ()
}
securityError(status: status)
return []
}
fileprivate class func prettify(itemClass: ItemClass, items: [[String: Any]]) -> [[String: Any]] {
let items = items.map { attributes -> [String: Any] in
var item = [String: Any]()
item["class"] = itemClass.description
if let accessGroup = attributes[AttributeAccessGroup] as? String {
item["accessGroup"] = accessGroup
}
switch itemClass {
case .genericPassword:
if let service = attributes[AttributeService] as? String {
item["service"] = service
}
case .internetPassword:
if let server = attributes[AttributeServer] as? String {
item["server"] = server
}
if let proto = attributes[AttributeProtocol] as? String {
if let protocolType = ProtocolType(rawValue: proto) {
item["protocol"] = protocolType.description
}
}
if let auth = attributes[AttributeAuthenticationType] as? String {
if let authenticationType = AuthenticationType(rawValue: auth) {
item["authenticationType"] = authenticationType.description
}
}
}
if let key = attributes[AttributeAccount] as? String {
item["key"] = key
}
if let data = attributes[ValueData] as? Data {
if let text = String(data: data, encoding: .utf8) {
item["value"] = text
} else {
item["value"] = data
}
}
if let accessible = attributes[AttributeAccessible] as? String {
if let accessibility = Accessibility(rawValue: accessible) {
item["accessibility"] = accessibility.description
}
}
if let synchronizable = attributes[AttributeSynchronizable] as? Bool {
item["synchronizable"] = synchronizable ? "true" : "false"
}
return item
}
return items
}
// MARK:
@discardableResult
fileprivate class func securityError(status: OSStatus) -> Error {
let error = Status(status: status)
if error != .userCanceled {
print("OSStatus error:[\(error.errorCode)] \(error.description)")
}
return error
}
@discardableResult
fileprivate func securityError(status: OSStatus) -> Error {
return type(of: self).securityError(status: status)
}
}
struct Options {
var itemClass: ItemClass = .genericPassword
var service: String = ""
var accessGroup: String? = nil
var server: URL!
var protocolType: ProtocolType!
var authenticationType: AuthenticationType = .default
var accessibility: Accessibility = .afterFirstUnlock
var authenticationPolicy: AuthenticationPolicy?
var synchronizable: Bool = false
var label: String?
var comment: String?
var authenticationPrompt: String?
var authenticationUI: AuthenticationUI?
var authenticationContext: AnyObject?
var attributes = [String: Any]()
}
/** Class Key Constant */
private let Class = String(kSecClass)
/** Attribute Key Constants */
private let AttributeAccessible = String(kSecAttrAccessible)
@available(iOS 8.0, OSX 10.10, *)
private let AttributeAccessControl = String(kSecAttrAccessControl)
private let AttributeAccessGroup = String(kSecAttrAccessGroup)
private let AttributeSynchronizable = String(kSecAttrSynchronizable)
private let AttributeCreationDate = String(kSecAttrCreationDate)
private let AttributeModificationDate = String(kSecAttrModificationDate)
private let AttributeDescription = String(kSecAttrDescription)
private let AttributeComment = String(kSecAttrComment)
private let AttributeCreator = String(kSecAttrCreator)
private let AttributeType = String(kSecAttrType)
private let AttributeLabel = String(kSecAttrLabel)
private let AttributeIsInvisible = String(kSecAttrIsInvisible)
private let AttributeIsNegative = String(kSecAttrIsNegative)
private let AttributeAccount = String(kSecAttrAccount)
private let AttributeService = String(kSecAttrService)
private let AttributeGeneric = String(kSecAttrGeneric)
private let AttributeSecurityDomain = String(kSecAttrSecurityDomain)
private let AttributeServer = String(kSecAttrServer)
private let AttributeProtocol = String(kSecAttrProtocol)
private let AttributeAuthenticationType = String(kSecAttrAuthenticationType)
private let AttributePort = String(kSecAttrPort)
private let AttributePath = String(kSecAttrPath)
private let SynchronizableAny = kSecAttrSynchronizableAny
/** Search Constants */
private let MatchLimit = String(kSecMatchLimit)
private let MatchLimitOne = kSecMatchLimitOne
private let MatchLimitAll = kSecMatchLimitAll
/** Return Type Key Constants */
private let ReturnData = String(kSecReturnData)
private let ReturnAttributes = String(kSecReturnAttributes)
private let ReturnRef = String(kSecReturnRef)
private let ReturnPersistentRef = String(kSecReturnPersistentRef)
/** Value Type Key Constants */
private let ValueData = String(kSecValueData)
private let ValueRef = String(kSecValueRef)
private let ValuePersistentRef = String(kSecValuePersistentRef)
/** Other Constants */
@available(iOS 8.0, OSX 10.10, tvOS 8.0, *)
private let UseOperationPrompt = String(kSecUseOperationPrompt)
@available(iOS, introduced: 8.0, deprecated: 9.0, message: "Use a UseAuthenticationUI instead.")
@available(OSX, introduced: 10.10, deprecated: 10.11, message: "Use UseAuthenticationUI instead.")
@available(watchOS, introduced: 2.0, deprecated: 2.0, message: "Use UseAuthenticationUI instead.")
@available(tvOS, introduced: 8.0, deprecated: 9.0, message: "Use UseAuthenticationUI instead.")
private let UseNoAuthenticationUI = String(kSecUseNoAuthenticationUI)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUI = String(kSecUseAuthenticationUI)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationContext = String(kSecUseAuthenticationContext)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUIAllow = String(kSecUseAuthenticationUIAllow)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUIFail = String(kSecUseAuthenticationUIFail)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUISkip = String(kSecUseAuthenticationUISkip)
#if os(iOS) && !targetEnvironment(macCatalyst)
/** Credential Key Constants */
private let SharedPassword = String(kSecSharedPassword)
#endif
extension Keychain: CustomStringConvertible, CustomDebugStringConvertible {
public var description: String {
let items = allItems()
if items.isEmpty {
return "[]"
}
var description = "[\n"
for item in items {
description += " "
description += "\(item)\n"
}
description += "]"
return description
}
public var debugDescription: String {
return "\(items())"
}
}
extension Options {
func query(ignoringAttributeSynchronizable: Bool = true) -> [String: Any] {
var query = [String: Any]()
query[Class] = itemClass.rawValue
if let accessGroup = self.accessGroup {
query[AttributeAccessGroup] = accessGroup
}
if ignoringAttributeSynchronizable {
query[AttributeSynchronizable] = SynchronizableAny
} else {
query[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
}
switch itemClass {
case .genericPassword:
query[AttributeService] = service
case .internetPassword:
query[AttributeServer] = server.host
query[AttributePort] = server.port
query[AttributeProtocol] = protocolType.rawValue
query[AttributeAuthenticationType] = authenticationType.rawValue
}
if #available(OSX 10.10, *) {
if authenticationPrompt != nil {
query[UseOperationPrompt] = authenticationPrompt
}
}
#if !os(watchOS)
if #available(iOS 9.0, OSX 10.11, *) {
if authenticationContext != nil {
query[UseAuthenticationContext] = authenticationContext
}
}
#endif
return query
}
func attributes(key: String?, value: Data) -> ([String: Any], Error?) {
var attributes: [String: Any]
if key != nil {
attributes = query()
attributes[AttributeAccount] = key
} else {
attributes = [String: Any]()
}
attributes[ValueData] = value
if label != nil {
attributes[AttributeLabel] = label
}
if comment != nil {
attributes[AttributeComment] = comment
}
if let policy = authenticationPolicy {
if #available(OSX 10.10, *) {
var error: Unmanaged?
guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, SecAccessControlCreateFlags(rawValue: CFOptionFlags(policy.rawValue)), &error) else {
if let error = error?.takeUnretainedValue() {
return (attributes, error.error)
}
return (attributes, Status.unexpectedError)
}
attributes[AttributeAccessControl] = accessControl
} else {
print("Unavailable 'Touch ID integration' on OS X versions prior to 10.10.")
}
} else {
attributes[AttributeAccessible] = accessibility.rawValue
}
attributes[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
return (attributes, nil)
}
}
// MARK:
extension Attributes: CustomStringConvertible, CustomDebugStringConvertible {
public var description: String {
return "\(attributes)"
}
public var debugDescription: String {
return description
}
}
extension ItemClass: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
switch rawValue {
case String(kSecClassGenericPassword):
self = .genericPassword
case String(kSecClassInternetPassword):
self = .internetPassword
default:
return nil
}
}
public var rawValue: String {
switch self {
case .genericPassword:
return String(kSecClassGenericPassword)
case .internetPassword:
return String(kSecClassInternetPassword)
}
}
public var description: String {
switch self {
case .genericPassword:
return "GenericPassword"
case .internetPassword:
return "InternetPassword"
}
}
}
extension ProtocolType: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
switch rawValue {
case String(kSecAttrProtocolFTP):
self = .ftp
case String(kSecAttrProtocolFTPAccount):
self = .ftpAccount
case String(kSecAttrProtocolHTTP):
self = .http
case String(kSecAttrProtocolIRC):
self = .irc
case String(kSecAttrProtocolNNTP):
self = .nntp
case String(kSecAttrProtocolPOP3):
self = .pop3
case String(kSecAttrProtocolSMTP):
self = .smtp
case String(kSecAttrProtocolSOCKS):
self = .socks
case String(kSecAttrProtocolIMAP):
self = .imap
case String(kSecAttrProtocolLDAP):
self = .ldap
case String(kSecAttrProtocolAppleTalk):
self = .appleTalk
case String(kSecAttrProtocolAFP):
self = .afp
case String(kSecAttrProtocolTelnet):
self = .telnet
case String(kSecAttrProtocolSSH):
self = .ssh
case String(kSecAttrProtocolFTPS):
self = .ftps
case String(kSecAttrProtocolHTTPS):
self = .https
case String(kSecAttrProtocolHTTPProxy):
self = .httpProxy
case String(kSecAttrProtocolHTTPSProxy):
self = .httpsProxy
case String(kSecAttrProtocolFTPProxy):
self = .ftpProxy
case String(kSecAttrProtocolSMB):
self = .smb
case String(kSecAttrProtocolRTSP):
self = .rtsp
case String(kSecAttrProtocolRTSPProxy):
self = .rtspProxy
case String(kSecAttrProtocolDAAP):
self = .daap
case String(kSecAttrProtocolEPPC):
self = .eppc
case String(kSecAttrProtocolIPP):
self = .ipp
case String(kSecAttrProtocolNNTPS):
self = .nntps
case String(kSecAttrProtocolLDAPS):
self = .ldaps
case String(kSecAttrProtocolTelnetS):
self = .telnetS
case String(kSecAttrProtocolIMAPS):
self = .imaps
case String(kSecAttrProtocolIRCS):
self = .ircs
case String(kSecAttrProtocolPOP3S):
self = .pop3S
default:
return nil
}
}
public var rawValue: String {
switch self {
case .ftp:
return String(kSecAttrProtocolFTP)
case .ftpAccount:
return String(kSecAttrProtocolFTPAccount)
case .http:
return String(kSecAttrProtocolHTTP)
case .irc:
return String(kSecAttrProtocolIRC)
case .nntp:
return String(kSecAttrProtocolNNTP)
case .pop3:
return String(kSecAttrProtocolPOP3)
case .smtp:
return String(kSecAttrProtocolSMTP)
case .socks:
return String(kSecAttrProtocolSOCKS)
case .imap:
return String(kSecAttrProtocolIMAP)
case .ldap:
return String(kSecAttrProtocolLDAP)
case .appleTalk:
return String(kSecAttrProtocolAppleTalk)
case .afp:
return String(kSecAttrProtocolAFP)
case .telnet:
return String(kSecAttrProtocolTelnet)
case .ssh:
return String(kSecAttrProtocolSSH)
case .ftps:
return String(kSecAttrProtocolFTPS)
case .https:
return String(kSecAttrProtocolHTTPS)
case .httpProxy:
return String(kSecAttrProtocolHTTPProxy)
case .httpsProxy:
return String(kSecAttrProtocolHTTPSProxy)
case .ftpProxy:
return String(kSecAttrProtocolFTPProxy)
case .smb:
return String(kSecAttrProtocolSMB)
case .rtsp:
return String(kSecAttrProtocolRTSP)
case .rtspProxy:
return String(kSecAttrProtocolRTSPProxy)
case .daap:
return String(kSecAttrProtocolDAAP)
case .eppc:
return String(kSecAttrProtocolEPPC)
case .ipp:
return String(kSecAttrProtocolIPP)
case .nntps:
return String(kSecAttrProtocolNNTPS)
case .ldaps:
return String(kSecAttrProtocolLDAPS)
case .telnetS:
return String(kSecAttrProtocolTelnetS)
case .imaps:
return String(kSecAttrProtocolIMAPS)
case .ircs:
return String(kSecAttrProtocolIRCS)
case .pop3S:
return String(kSecAttrProtocolPOP3S)
}
}
public var description: String {
switch self {
case .ftp:
return "FTP"
case .ftpAccount:
return "FTPAccount"
case .http:
return "HTTP"
case .irc:
return "IRC"
case .nntp:
return "NNTP"
case .pop3:
return "POP3"
case .smtp:
return "SMTP"
case .socks:
return "SOCKS"
case .imap:
return "IMAP"
case .ldap:
return "LDAP"
case .appleTalk:
return "AppleTalk"
case .afp:
return "AFP"
case .telnet:
return "Telnet"
case .ssh:
return "SSH"
case .ftps:
return "FTPS"
case .https:
return "HTTPS"
case .httpProxy:
return "HTTPProxy"
case .httpsProxy:
return "HTTPSProxy"
case .ftpProxy:
return "FTPProxy"
case .smb:
return "SMB"
case .rtsp:
return "RTSP"
case .rtspProxy:
return "RTSPProxy"
case .daap:
return "DAAP"
case .eppc:
return "EPPC"
case .ipp:
return "IPP"
case .nntps:
return "NNTPS"
case .ldaps:
return "LDAPS"
case .telnetS:
return "TelnetS"
case .imaps:
return "IMAPS"
case .ircs:
return "IRCS"
case .pop3S:
return "POP3S"
}
}
}
extension AuthenticationType: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
switch rawValue {
case String(kSecAttrAuthenticationTypeNTLM):
self = .ntlm
case String(kSecAttrAuthenticationTypeMSN):
self = .msn
case String(kSecAttrAuthenticationTypeDPA):
self = .dpa
case String(kSecAttrAuthenticationTypeRPA):
self = .rpa
case String(kSecAttrAuthenticationTypeHTTPBasic):
self = .httpBasic
case String(kSecAttrAuthenticationTypeHTTPDigest):
self = .httpDigest
case String(kSecAttrAuthenticationTypeHTMLForm):
self = .htmlForm
case String(kSecAttrAuthenticationTypeDefault):
self = .`default`
default:
return nil
}
}
public var rawValue: String {
switch self {
case .ntlm:
return String(kSecAttrAuthenticationTypeNTLM)
case .msn:
return String(kSecAttrAuthenticationTypeMSN)
case .dpa:
return String(kSecAttrAuthenticationTypeDPA)
case .rpa:
return String(kSecAttrAuthenticationTypeRPA)
case .httpBasic:
return String(kSecAttrAuthenticationTypeHTTPBasic)
case .httpDigest:
return String(kSecAttrAuthenticationTypeHTTPDigest)
case .htmlForm:
return String(kSecAttrAuthenticationTypeHTMLForm)
case .`default`:
return String(kSecAttrAuthenticationTypeDefault)
}
}
public var description: String {
switch self {
case .ntlm:
return "NTLM"
case .msn:
return "MSN"
case .dpa:
return "DPA"
case .rpa:
return "RPA"
case .httpBasic:
return "HTTPBasic"
case .httpDigest:
return "HTTPDigest"
case .htmlForm:
return "HTMLForm"
case .`default`:
return "Default"
}
}
}
extension Accessibility: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
if #available(OSX 10.10, *) {
switch rawValue {
case String(kSecAttrAccessibleWhenUnlocked):
self = .whenUnlocked
case String(kSecAttrAccessibleAfterFirstUnlock):
self = .afterFirstUnlock
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlways):
self = .always
#endif
case String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly):
self = .whenPasscodeSetThisDeviceOnly
case String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly):
self = .whenUnlockedThisDeviceOnly
case String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly):
self = .afterFirstUnlockThisDeviceOnly
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlwaysThisDeviceOnly):
self = .alwaysThisDeviceOnly
#endif
default:
return nil
}
} else {
switch rawValue {
case String(kSecAttrAccessibleWhenUnlocked):
self = .whenUnlocked
case String(kSecAttrAccessibleAfterFirstUnlock):
self = .afterFirstUnlock
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlways):
self = .always
#endif
case String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly):
self = .whenUnlockedThisDeviceOnly
case String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly):
self = .afterFirstUnlockThisDeviceOnly
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlwaysThisDeviceOnly):
self = .alwaysThisDeviceOnly
#endif
default:
return nil
}
}
}
public var rawValue: String {
switch self {
case .whenUnlocked:
return String(kSecAttrAccessibleWhenUnlocked)
case .afterFirstUnlock:
return String(kSecAttrAccessibleAfterFirstUnlock)
#if !targetEnvironment(macCatalyst)
case .always:
return String(kSecAttrAccessibleAlways)
#endif
case .whenPasscodeSetThisDeviceOnly:
if #available(OSX 10.10, *) {
return String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)
} else {
fatalError("'Accessibility.WhenPasscodeSetThisDeviceOnly' is not available on this version of OS.")
}
case .whenUnlockedThisDeviceOnly:
return String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
case .afterFirstUnlockThisDeviceOnly:
return String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
#if !targetEnvironment(macCatalyst)
case .alwaysThisDeviceOnly:
return String(kSecAttrAccessibleAlwaysThisDeviceOnly)
#endif
}
}
public var description: String {
switch self {
case .whenUnlocked:
return "WhenUnlocked"
case .afterFirstUnlock:
return "AfterFirstUnlock"
#if !targetEnvironment(macCatalyst)
case .always:
return "Always"
#endif
case .whenPasscodeSetThisDeviceOnly:
return "WhenPasscodeSetThisDeviceOnly"
case .whenUnlockedThisDeviceOnly:
return "WhenUnlockedThisDeviceOnly"
case .afterFirstUnlockThisDeviceOnly:
return "AfterFirstUnlockThisDeviceOnly"
#if !targetEnvironment(macCatalyst)
case .alwaysThisDeviceOnly:
return "AlwaysThisDeviceOnly"
#endif
}
}
}
extension CFError {
var error: NSError {
let domain = CFErrorGetDomain(self) as String
let code = CFErrorGetCode(self)
let userInfo = CFErrorCopyUserInfo(self) as! [String: Any]
return NSError(domain: domain, code: code, userInfo: userInfo)
}
}
public enum Status: OSStatus, Error {
case success = 0
case unimplemented = -4
case diskFull = -34
case io = -36
case opWr = -49
case param = -50
case wrPerm = -61
case allocate = -108
case userCanceled = -128
case badReq = -909
case internalComponent = -2070
case notAvailable = -25291
case readOnly = -25292
case authFailed = -25293
case noSuchKeychain = -25294
case invalidKeychain = -25295
case duplicateKeychain = -25296
case duplicateCallback = -25297
case invalidCallback = -25298
case duplicateItem = -25299
case itemNotFound = -25300
case bufferTooSmall = -25301
case dataTooLarge = -25302
case noSuchAttr = -25303
case invalidItemRef = -25304
case invalidSearchRef = -25305
case noSuchClass = -25306
case noDefaultKeychain = -25307
case interactionNotAllowed = -25308
case readOnlyAttr = -25309
case wrongSecVersion = -25310
case keySizeNotAllowed = -25311
case noStorageModule = -25312
case noCertificateModule = -25313
case noPolicyModule = -25314
case interactionRequired = -25315
case dataNotAvailable = -25316
case dataNotModifiable = -25317
case createChainFailed = -25318
case invalidPrefsDomain = -25319
case inDarkWake = -25320
case aclNotSimple = -25240
case policyNotFound = -25241
case invalidTrustSetting = -25242
case noAccessForItem = -25243
case invalidOwnerEdit = -25244
case trustNotAvailable = -25245
case unsupportedFormat = -25256
case unknownFormat = -25257
case keyIsSensitive = -25258
case multiplePrivKeys = -25259
case passphraseRequired = -25260
case invalidPasswordRef = -25261
case invalidTrustSettings = -25262
case noTrustSettings = -25263
case pkcs12VerifyFailure = -25264
case invalidCertificate = -26265
case notSigner = -26267
case policyDenied = -26270
case invalidKey = -26274
case decode = -26275
case `internal` = -26276
case unsupportedAlgorithm = -26268
case unsupportedOperation = -26271
case unsupportedPadding = -26273
case itemInvalidKey = -34000
case itemInvalidKeyType = -34001
case itemInvalidValue = -34002
case itemClassMissing = -34003
case itemMatchUnsupported = -34004
case useItemListUnsupported = -34005
case useKeychainUnsupported = -34006
case useKeychainListUnsupported = -34007
case returnDataUnsupported = -34008
case returnAttributesUnsupported = -34009
case returnRefUnsupported = -34010
case returnPersitentRefUnsupported = -34011
case valueRefUnsupported = -34012
case valuePersistentRefUnsupported = -34013
case returnMissingPointer = -34014
case matchLimitUnsupported = -34015
case itemIllegalQuery = -34016
case waitForCallback = -34017
case missingEntitlement = -34018
case upgradePending = -34019
case mpSignatureInvalid = -25327
case otrTooOld = -25328
case otrIDTooNew = -25329
case serviceNotAvailable = -67585
case insufficientClientID = -67586
case deviceReset = -67587
case deviceFailed = -67588
case appleAddAppACLSubject = -67589
case applePublicKeyIncomplete = -67590
case appleSignatureMismatch = -67591
case appleInvalidKeyStartDate = -67592
case appleInvalidKeyEndDate = -67593
case conversionError = -67594
case appleSSLv2Rollback = -67595
case quotaExceeded = -67596
case fileTooBig = -67597
case invalidDatabaseBlob = -67598
case invalidKeyBlob = -67599
case incompatibleDatabaseBlob = -67600
case incompatibleKeyBlob = -67601
case hostNameMismatch = -67602
case unknownCriticalExtensionFlag = -67603
case noBasicConstraints = -67604
case noBasicConstraintsCA = -67605
case invalidAuthorityKeyID = -67606
case invalidSubjectKeyID = -67607
case invalidKeyUsageForPolicy = -67608
case invalidExtendedKeyUsage = -67609
case invalidIDLinkage = -67610
case pathLengthConstraintExceeded = -67611
case invalidRoot = -67612
case crlExpired = -67613
case crlNotValidYet = -67614
case crlNotFound = -67615
case crlServerDown = -67616
case crlBadURI = -67617
case unknownCertExtension = -67618
case unknownCRLExtension = -67619
case crlNotTrusted = -67620
case crlPolicyFailed = -67621
case idpFailure = -67622
case smimeEmailAddressesNotFound = -67623
case smimeBadExtendedKeyUsage = -67624
case smimeBadKeyUsage = -67625
case smimeKeyUsageNotCritical = -67626
case smimeNoEmailAddress = -67627
case smimeSubjAltNameNotCritical = -67628
case sslBadExtendedKeyUsage = -67629
case ocspBadResponse = -67630
case ocspBadRequest = -67631
case ocspUnavailable = -67632
case ocspStatusUnrecognized = -67633
case endOfData = -67634
case incompleteCertRevocationCheck = -67635
case networkFailure = -67636
case ocspNotTrustedToAnchor = -67637
case recordModified = -67638
case ocspSignatureError = -67639
case ocspNoSigner = -67640
case ocspResponderMalformedReq = -67641
case ocspResponderInternalError = -67642
case ocspResponderTryLater = -67643
case ocspResponderSignatureRequired = -67644
case ocspResponderUnauthorized = -67645
case ocspResponseNonceMismatch = -67646
case codeSigningBadCertChainLength = -67647
case codeSigningNoBasicConstraints = -67648
case codeSigningBadPathLengthConstraint = -67649
case codeSigningNoExtendedKeyUsage = -67650
case codeSigningDevelopment = -67651
case resourceSignBadCertChainLength = -67652
case resourceSignBadExtKeyUsage = -67653
case trustSettingDeny = -67654
case invalidSubjectName = -67655
case unknownQualifiedCertStatement = -67656
case mobileMeRequestQueued = -67657
case mobileMeRequestRedirected = -67658
case mobileMeServerError = -67659
case mobileMeServerNotAvailable = -67660
case mobileMeServerAlreadyExists = -67661
case mobileMeServerServiceErr = -67662
case mobileMeRequestAlreadyPending = -67663
case mobileMeNoRequestPending = -67664
case mobileMeCSRVerifyFailure = -67665
case mobileMeFailedConsistencyCheck = -67666
case notInitialized = -67667
case invalidHandleUsage = -67668
case pvcReferentNotFound = -67669
case functionIntegrityFail = -67670
case internalError = -67671
case memoryError = -67672
case invalidData = -67673
case mdsError = -67674
case invalidPointer = -67675
case selfCheckFailed = -67676
case functionFailed = -67677
case moduleManifestVerifyFailed = -67678
case invalidGUID = -67679
case invalidHandle = -67680
case invalidDBList = -67681
case invalidPassthroughID = -67682
case invalidNetworkAddress = -67683
case crlAlreadySigned = -67684
case invalidNumberOfFields = -67685
case verificationFailure = -67686
case unknownTag = -67687
case invalidSignature = -67688
case invalidName = -67689
case invalidCertificateRef = -67690
case invalidCertificateGroup = -67691
case tagNotFound = -67692
case invalidQuery = -67693
case invalidValue = -67694
case callbackFailed = -67695
case aclDeleteFailed = -67696
case aclReplaceFailed = -67697
case aclAddFailed = -67698
case aclChangeFailed = -67699
case invalidAccessCredentials = -67700
case invalidRecord = -67701
case invalidACL = -67702
case invalidSampleValue = -67703
case incompatibleVersion = -67704
case privilegeNotGranted = -67705
case invalidScope = -67706
case pvcAlreadyConfigured = -67707
case invalidPVC = -67708
case emmLoadFailed = -67709
case emmUnloadFailed = -67710
case addinLoadFailed = -67711
case invalidKeyRef = -67712
case invalidKeyHierarchy = -67713
case addinUnloadFailed = -67714
case libraryReferenceNotFound = -67715
case invalidAddinFunctionTable = -67716
case invalidServiceMask = -67717
case moduleNotLoaded = -67718
case invalidSubServiceID = -67719
case attributeNotInContext = -67720
case moduleManagerInitializeFailed = -67721
case moduleManagerNotFound = -67722
case eventNotificationCallbackNotFound = -67723
case inputLengthError = -67724
case outputLengthError = -67725
case privilegeNotSupported = -67726
case deviceError = -67727
case attachHandleBusy = -67728
case notLoggedIn = -67729
case algorithmMismatch = -67730
case keyUsageIncorrect = -67731
case keyBlobTypeIncorrect = -67732
case keyHeaderInconsistent = -67733
case unsupportedKeyFormat = -67734
case unsupportedKeySize = -67735
case invalidKeyUsageMask = -67736
case unsupportedKeyUsageMask = -67737
case invalidKeyAttributeMask = -67738
case unsupportedKeyAttributeMask = -67739
case invalidKeyLabel = -67740
case unsupportedKeyLabel = -67741
case invalidKeyFormat = -67742
case unsupportedVectorOfBuffers = -67743
case invalidInputVector = -67744
case invalidOutputVector = -67745
case invalidContext = -67746
case invalidAlgorithm = -67747
case invalidAttributeKey = -67748
case missingAttributeKey = -67749
case invalidAttributeInitVector = -67750
case missingAttributeInitVector = -67751
case invalidAttributeSalt = -67752
case missingAttributeSalt = -67753
case invalidAttributePadding = -67754
case missingAttributePadding = -67755
case invalidAttributeRandom = -67756
case missingAttributeRandom = -67757
case invalidAttributeSeed = -67758
case missingAttributeSeed = -67759
case invalidAttributePassphrase = -67760
case missingAttributePassphrase = -67761
case invalidAttributeKeyLength = -67762
case missingAttributeKeyLength = -67763
case invalidAttributeBlockSize = -67764
case missingAttributeBlockSize = -67765
case invalidAttributeOutputSize = -67766
case missingAttributeOutputSize = -67767
case invalidAttributeRounds = -67768
case missingAttributeRounds = -67769
case invalidAlgorithmParms = -67770
case missingAlgorithmParms = -67771
case invalidAttributeLabel = -67772
case missingAttributeLabel = -67773
case invalidAttributeKeyType = -67774
case missingAttributeKeyType = -67775
case invalidAttributeMode = -67776
case missingAttributeMode = -67777
case invalidAttributeEffectiveBits = -67778
case missingAttributeEffectiveBits = -67779
case invalidAttributeStartDate = -67780
case missingAttributeStartDate = -67781
case invalidAttributeEndDate = -67782
case missingAttributeEndDate = -67783
case invalidAttributeVersion = -67784
case missingAttributeVersion = -67785
case invalidAttributePrime = -67786
case missingAttributePrime = -67787
case invalidAttributeBase = -67788
case missingAttributeBase = -67789
case invalidAttributeSubprime = -67790
case missingAttributeSubprime = -67791
case invalidAttributeIterationCount = -67792
case missingAttributeIterationCount = -67793
case invalidAttributeDLDBHandle = -67794
case missingAttributeDLDBHandle = -67795
case invalidAttributeAccessCredentials = -67796
case missingAttributeAccessCredentials = -67797
case invalidAttributePublicKeyFormat = -67798
case missingAttributePublicKeyFormat = -67799
case invalidAttributePrivateKeyFormat = -67800
case missingAttributePrivateKeyFormat = -67801
case invalidAttributeSymmetricKeyFormat = -67802
case missingAttributeSymmetricKeyFormat = -67803
case invalidAttributeWrappedKeyFormat = -67804
case missingAttributeWrappedKeyFormat = -67805
case stagedOperationInProgress = -67806
case stagedOperationNotStarted = -67807
case verifyFailed = -67808
case querySizeUnknown = -67809
case blockSizeMismatch = -67810
case publicKeyInconsistent = -67811
case deviceVerifyFailed = -67812
case invalidLoginName = -67813
case alreadyLoggedIn = -67814
case invalidDigestAlgorithm = -67815
case invalidCRLGroup = -67816
case certificateCannotOperate = -67817
case certificateExpired = -67818
case certificateNotValidYet = -67819
case certificateRevoked = -67820
case certificateSuspended = -67821
case insufficientCredentials = -67822
case invalidAction = -67823
case invalidAuthority = -67824
case verifyActionFailed = -67825
case invalidCertAuthority = -67826
case invaldCRLAuthority = -67827
case invalidCRLEncoding = -67828
case invalidCRLType = -67829
case invalidCRL = -67830
case invalidFormType = -67831
case invalidID = -67832
case invalidIdentifier = -67833
case invalidIndex = -67834
case invalidPolicyIdentifiers = -67835
case invalidTimeString = -67836
case invalidReason = -67837
case invalidRequestInputs = -67838
case invalidResponseVector = -67839
case invalidStopOnPolicy = -67840
case invalidTuple = -67841
case multipleValuesUnsupported = -67842
case notTrusted = -67843
case noDefaultAuthority = -67844
case rejectedForm = -67845
case requestLost = -67846
case requestRejected = -67847
case unsupportedAddressType = -67848
case unsupportedService = -67849
case invalidTupleGroup = -67850
case invalidBaseACLs = -67851
case invalidTupleCredendtials = -67852
case invalidEncoding = -67853
case invalidValidityPeriod = -67854
case invalidRequestor = -67855
case requestDescriptor = -67856
case invalidBundleInfo = -67857
case invalidCRLIndex = -67858
case noFieldValues = -67859
case unsupportedFieldFormat = -67860
case unsupportedIndexInfo = -67861
case unsupportedLocality = -67862
case unsupportedNumAttributes = -67863
case unsupportedNumIndexes = -67864
case unsupportedNumRecordTypes = -67865
case fieldSpecifiedMultiple = -67866
case incompatibleFieldFormat = -67867
case invalidParsingModule = -67868
case databaseLocked = -67869
case datastoreIsOpen = -67870
case missingValue = -67871
case unsupportedQueryLimits = -67872
case unsupportedNumSelectionPreds = -67873
case unsupportedOperator = -67874
case invalidDBLocation = -67875
case invalidAccessRequest = -67876
case invalidIndexInfo = -67877
case invalidNewOwner = -67878
case invalidModifyMode = -67879
case missingRequiredExtension = -67880
case extendedKeyUsageNotCritical = -67881
case timestampMissing = -67882
case timestampInvalid = -67883
case timestampNotTrusted = -67884
case timestampServiceNotAvailable = -67885
case timestampBadAlg = -67886
case timestampBadRequest = -67887
case timestampBadDataFormat = -67888
case timestampTimeNotAvailable = -67889
case timestampUnacceptedPolicy = -67890
case timestampUnacceptedExtension = -67891
case timestampAddInfoNotAvailable = -67892
case timestampSystemFailure = -67893
case signingTimeMissing = -67894
case timestampRejection = -67895
case timestampWaiting = -67896
case timestampRevocationWarning = -67897
case timestampRevocationNotification = -67898
case unexpectedError = -99999
}
extension Status: RawRepresentable, CustomStringConvertible {
public init(status: OSStatus) {
if let mappedStatus = Status(rawValue: status) {
self = mappedStatus
} else {
self = .unexpectedError
}
}
public var description: String {
switch self {
case .success:
return "No error."
case .unimplemented:
return "Function or operation not implemented."
case .diskFull:
return "The disk is full."
case .io:
return "I/O error (bummers)"
case .opWr:
return "file already open with with write permission"
case .param:
return "One or more parameters passed to a function were not valid."
case .wrPerm:
return "write permissions error"
case .allocate:
return "Failed to allocate memory."
case .userCanceled:
return "User canceled the operation."
case .badReq:
return "Bad parameter or invalid state for operation."
case .internalComponent:
return ""
case .notAvailable:
return "No keychain is available. You may need to restart your computer."
case .readOnly:
return "This keychain cannot be modified."
case .authFailed:
return "The user name or passphrase you entered is not correct."
case .noSuchKeychain:
return "The specified keychain could not be found."
case .invalidKeychain:
return "The specified keychain is not a valid keychain file."
case .duplicateKeychain:
return "A keychain with the same name already exists."
case .duplicateCallback:
return "The specified callback function is already installed."
case .invalidCallback:
return "The specified callback function is not valid."
case .duplicateItem:
return "The specified item already exists in the keychain."
case .itemNotFound:
return "The specified item could not be found in the keychain."
case .bufferTooSmall:
return "There is not enough memory available to use the specified item."
case .dataTooLarge:
return "This item contains information which is too large or in a format that cannot be displayed."
case .noSuchAttr:
return "The specified attribute does not exist."
case .invalidItemRef:
return "The specified item is no longer valid. It may have been deleted from the keychain."
case .invalidSearchRef:
return "Unable to search the current keychain."
case .noSuchClass:
return "The specified item does not appear to be a valid keychain item."
case .noDefaultKeychain:
return "A default keychain could not be found."
case .interactionNotAllowed:
return "User interaction is not allowed."
case .readOnlyAttr:
return "The specified attribute could not be modified."
case .wrongSecVersion:
return "This keychain was created by a different version of the system software and cannot be opened."
case .keySizeNotAllowed:
return "This item specifies a key size which is too large."
case .noStorageModule:
return "A required component (data storage module) could not be loaded. You may need to restart your computer."
case .noCertificateModule:
return "A required component (certificate module) could not be loaded. You may need to restart your computer."
case .noPolicyModule:
return "A required component (policy module) could not be loaded. You may need to restart your computer."
case .interactionRequired:
return "User interaction is required, but is currently not allowed."
case .dataNotAvailable:
return "The contents of this item cannot be retrieved."
case .dataNotModifiable:
return "The contents of this item cannot be modified."
case .createChainFailed:
return "One or more certificates required to validate this certificate cannot be found."
case .invalidPrefsDomain:
return "The specified preferences domain is not valid."
case .inDarkWake:
return "In dark wake, no UI possible"
case .aclNotSimple:
return "The specified access control list is not in standard (simple) form."
case .policyNotFound:
return "The specified policy cannot be found."
case .invalidTrustSetting:
return "The specified trust setting is invalid."
case .noAccessForItem:
return "The specified item has no access control."
case .invalidOwnerEdit:
return "Invalid attempt to change the owner of this item."
case .trustNotAvailable:
return "No trust results are available."
case .unsupportedFormat:
return "Import/Export format unsupported."
case .unknownFormat:
return "Unknown format in import."
case .keyIsSensitive:
return "Key material must be wrapped for export."
case .multiplePrivKeys:
return "An attempt was made to import multiple private keys."
case .passphraseRequired:
return "Passphrase is required for import/export."
case .invalidPasswordRef:
return "The password reference was invalid."
case .invalidTrustSettings:
return "The Trust Settings Record was corrupted."
case .noTrustSettings:
return "No Trust Settings were found."
case .pkcs12VerifyFailure:
return "MAC verification failed during PKCS12 import (wrong password?)"
case .invalidCertificate:
return "This certificate could not be decoded."
case .notSigner:
return "A certificate was not signed by its proposed parent."
case .policyDenied:
return "The certificate chain was not trusted due to a policy not accepting it."
case .invalidKey:
return "The provided key material was not valid."
case .decode:
return "Unable to decode the provided data."
case .`internal`:
return "An internal error occurred in the Security framework."
case .unsupportedAlgorithm:
return "An unsupported algorithm was encountered."
case .unsupportedOperation:
return "The operation you requested is not supported by this key."
case .unsupportedPadding:
return "The padding you requested is not supported."
case .itemInvalidKey:
return "A string key in dictionary is not one of the supported keys."
case .itemInvalidKeyType:
return "A key in a dictionary is neither a CFStringRef nor a CFNumberRef."
case .itemInvalidValue:
return "A value in a dictionary is an invalid (or unsupported) CF type."
case .itemClassMissing:
return "No kSecItemClass key was specified in a dictionary."
case .itemMatchUnsupported:
return "The caller passed one or more kSecMatch keys to a function which does not support matches."
case .useItemListUnsupported:
return "The caller passed in a kSecUseItemList key to a function which does not support it."
case .useKeychainUnsupported:
return "The caller passed in a kSecUseKeychain key to a function which does not support it."
case .useKeychainListUnsupported:
return "The caller passed in a kSecUseKeychainList key to a function which does not support it."
case .returnDataUnsupported:
return "The caller passed in a kSecReturnData key to a function which does not support it."
case .returnAttributesUnsupported:
return "The caller passed in a kSecReturnAttributes key to a function which does not support it."
case .returnRefUnsupported:
return "The caller passed in a kSecReturnRef key to a function which does not support it."
case .returnPersitentRefUnsupported:
return "The caller passed in a kSecReturnPersistentRef key to a function which does not support it."
case .valueRefUnsupported:
return "The caller passed in a kSecValueRef key to a function which does not support it."
case .valuePersistentRefUnsupported:
return "The caller passed in a kSecValuePersistentRef key to a function which does not support it."
case .returnMissingPointer:
return "The caller passed asked for something to be returned but did not pass in a result pointer."
case .matchLimitUnsupported:
return "The caller passed in a kSecMatchLimit key to a call which does not support limits."
case .itemIllegalQuery:
return "The caller passed in a query which contained too many keys."
case .waitForCallback:
return "This operation is incomplete, until the callback is invoked (not an error)."
case .missingEntitlement:
return "Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements."
case .upgradePending:
return "Error returned if keychain database needs a schema migration but the device is locked, clients should wait for a device unlock notification and retry the command."
case .mpSignatureInvalid:
return "Signature invalid on MP message"
case .otrTooOld:
return "Message is too old to use"
case .otrIDTooNew:
return "Key ID is too new to use! Message from the future?"
case .serviceNotAvailable:
return "The required service is not available."
case .insufficientClientID:
return "The client ID is not correct."
case .deviceReset:
return "A device reset has occurred."
case .deviceFailed:
return "A device failure has occurred."
case .appleAddAppACLSubject:
return "Adding an application ACL subject failed."
case .applePublicKeyIncomplete:
return "The public key is incomplete."
case .appleSignatureMismatch:
return "A signature mismatch has occurred."
case .appleInvalidKeyStartDate:
return "The specified key has an invalid start date."
case .appleInvalidKeyEndDate:
return "The specified key has an invalid end date."
case .conversionError:
return "A conversion error has occurred."
case .appleSSLv2Rollback:
return "A SSLv2 rollback error has occurred."
case .quotaExceeded:
return "The quota was exceeded."
case .fileTooBig:
return "The file is too big."
case .invalidDatabaseBlob:
return "The specified database has an invalid blob."
case .invalidKeyBlob:
return "The specified database has an invalid key blob."
case .incompatibleDatabaseBlob:
return "The specified database has an incompatible blob."
case .incompatibleKeyBlob:
return "The specified database has an incompatible key blob."
case .hostNameMismatch:
return "A host name mismatch has occurred."
case .unknownCriticalExtensionFlag:
return "There is an unknown critical extension flag."
case .noBasicConstraints:
return "No basic constraints were found."
case .noBasicConstraintsCA:
return "No basic CA constraints were found."
case .invalidAuthorityKeyID:
return "The authority key ID is not valid."
case .invalidSubjectKeyID:
return "The subject key ID is not valid."
case .invalidKeyUsageForPolicy:
return "The key usage is not valid for the specified policy."
case .invalidExtendedKeyUsage:
return "The extended key usage is not valid."
case .invalidIDLinkage:
return "The ID linkage is not valid."
case .pathLengthConstraintExceeded:
return "The path length constraint was exceeded."
case .invalidRoot:
return "The root or anchor certificate is not valid."
case .crlExpired:
return "The CRL has expired."
case .crlNotValidYet:
return "The CRL is not yet valid."
case .crlNotFound:
return "The CRL was not found."
case .crlServerDown:
return "The CRL server is down."
case .crlBadURI:
return "The CRL has a bad Uniform Resource Identifier."
case .unknownCertExtension:
return "An unknown certificate extension was encountered."
case .unknownCRLExtension:
return "An unknown CRL extension was encountered."
case .crlNotTrusted:
return "The CRL is not trusted."
case .crlPolicyFailed:
return "The CRL policy failed."
case .idpFailure:
return "The issuing distribution point was not valid."
case .smimeEmailAddressesNotFound:
return "An email address mismatch was encountered."
case .smimeBadExtendedKeyUsage:
return "The appropriate extended key usage for SMIME was not found."
case .smimeBadKeyUsage:
return "The key usage is not compatible with SMIME."
case .smimeKeyUsageNotCritical:
return "The key usage extension is not marked as critical."
case .smimeNoEmailAddress:
return "No email address was found in the certificate."
case .smimeSubjAltNameNotCritical:
return "The subject alternative name extension is not marked as critical."
case .sslBadExtendedKeyUsage:
return "The appropriate extended key usage for SSL was not found."
case .ocspBadResponse:
return "The OCSP response was incorrect or could not be parsed."
case .ocspBadRequest:
return "The OCSP request was incorrect or could not be parsed."
case .ocspUnavailable:
return "OCSP service is unavailable."
case .ocspStatusUnrecognized:
return "The OCSP server did not recognize this certificate."
case .endOfData:
return "An end-of-data was detected."
case .incompleteCertRevocationCheck:
return "An incomplete certificate revocation check occurred."
case .networkFailure:
return "A network failure occurred."
case .ocspNotTrustedToAnchor:
return "The OCSP response was not trusted to a root or anchor certificate."
case .recordModified:
return "The record was modified."
case .ocspSignatureError:
return "The OCSP response had an invalid signature."
case .ocspNoSigner:
return "The OCSP response had no signer."
case .ocspResponderMalformedReq:
return "The OCSP responder was given a malformed request."
case .ocspResponderInternalError:
return "The OCSP responder encountered an internal error."
case .ocspResponderTryLater:
return "The OCSP responder is busy, try again later."
case .ocspResponderSignatureRequired:
return "The OCSP responder requires a signature."
case .ocspResponderUnauthorized:
return "The OCSP responder rejected this request as unauthorized."
case .ocspResponseNonceMismatch:
return "The OCSP response nonce did not match the request."
case .codeSigningBadCertChainLength:
return "Code signing encountered an incorrect certificate chain length."
case .codeSigningNoBasicConstraints:
return "Code signing found no basic constraints."
case .codeSigningBadPathLengthConstraint:
return "Code signing encountered an incorrect path length constraint."
case .codeSigningNoExtendedKeyUsage:
return "Code signing found no extended key usage."
case .codeSigningDevelopment:
return "Code signing indicated use of a development-only certificate."
case .resourceSignBadCertChainLength:
return "Resource signing has encountered an incorrect certificate chain length."
case .resourceSignBadExtKeyUsage:
return "Resource signing has encountered an error in the extended key usage."
case .trustSettingDeny:
return "The trust setting for this policy was set to Deny."
case .invalidSubjectName:
return "An invalid certificate subject name was encountered."
case .unknownQualifiedCertStatement:
return "An unknown qualified certificate statement was encountered."
case .mobileMeRequestQueued:
return "The MobileMe request will be sent during the next connection."
case .mobileMeRequestRedirected:
return "The MobileMe request was redirected."
case .mobileMeServerError:
return "A MobileMe server error occurred."
case .mobileMeServerNotAvailable:
return "The MobileMe server is not available."
case .mobileMeServerAlreadyExists:
return "The MobileMe server reported that the item already exists."
case .mobileMeServerServiceErr:
return "A MobileMe service error has occurred."
case .mobileMeRequestAlreadyPending:
return "A MobileMe request is already pending."
case .mobileMeNoRequestPending:
return "MobileMe has no request pending."
case .mobileMeCSRVerifyFailure:
return "A MobileMe CSR verification failure has occurred."
case .mobileMeFailedConsistencyCheck:
return "MobileMe has found a failed consistency check."
case .notInitialized:
return "A function was called without initializing CSSM."
case .invalidHandleUsage:
return "The CSSM handle does not match with the service type."
case .pvcReferentNotFound:
return "A reference to the calling module was not found in the list of authorized callers."
case .functionIntegrityFail:
return "A function address was not within the verified module."
case .internalError:
return "An internal error has occurred."
case .memoryError:
return "A memory error has occurred."
case .invalidData:
return "Invalid data was encountered."
case .mdsError:
return "A Module Directory Service error has occurred."
case .invalidPointer:
return "An invalid pointer was encountered."
case .selfCheckFailed:
return "Self-check has failed."
case .functionFailed:
return "A function has failed."
case .moduleManifestVerifyFailed:
return "A module manifest verification failure has occurred."
case .invalidGUID:
return "An invalid GUID was encountered."
case .invalidHandle:
return "An invalid handle was encountered."
case .invalidDBList:
return "An invalid DB list was encountered."
case .invalidPassthroughID:
return "An invalid passthrough ID was encountered."
case .invalidNetworkAddress:
return "An invalid network address was encountered."
case .crlAlreadySigned:
return "The certificate revocation list is already signed."
case .invalidNumberOfFields:
return "An invalid number of fields were encountered."
case .verificationFailure:
return "A verification failure occurred."
case .unknownTag:
return "An unknown tag was encountered."
case .invalidSignature:
return "An invalid signature was encountered."
case .invalidName:
return "An invalid name was encountered."
case .invalidCertificateRef:
return "An invalid certificate reference was encountered."
case .invalidCertificateGroup:
return "An invalid certificate group was encountered."
case .tagNotFound:
return "The specified tag was not found."
case .invalidQuery:
return "The specified query was not valid."
case .invalidValue:
return "An invalid value was detected."
case .callbackFailed:
return "A callback has failed."
case .aclDeleteFailed:
return "An ACL delete operation has failed."
case .aclReplaceFailed:
return "An ACL replace operation has failed."
case .aclAddFailed:
return "An ACL add operation has failed."
case .aclChangeFailed:
return "An ACL change operation has failed."
case .invalidAccessCredentials:
return "Invalid access credentials were encountered."
case .invalidRecord:
return "An invalid record was encountered."
case .invalidACL:
return "An invalid ACL was encountered."
case .invalidSampleValue:
return "An invalid sample value was encountered."
case .incompatibleVersion:
return "An incompatible version was encountered."
case .privilegeNotGranted:
return "The privilege was not granted."
case .invalidScope:
return "An invalid scope was encountered."
case .pvcAlreadyConfigured:
return "The PVC is already configured."
case .invalidPVC:
return "An invalid PVC was encountered."
case .emmLoadFailed:
return "The EMM load has failed."
case .emmUnloadFailed:
return "The EMM unload has failed."
case .addinLoadFailed:
return "The add-in load operation has failed."
case .invalidKeyRef:
return "An invalid key was encountered."
case .invalidKeyHierarchy:
return "An invalid key hierarchy was encountered."
case .addinUnloadFailed:
return "The add-in unload operation has failed."
case .libraryReferenceNotFound:
return "A library reference was not found."
case .invalidAddinFunctionTable:
return "An invalid add-in function table was encountered."
case .invalidServiceMask:
return "An invalid service mask was encountered."
case .moduleNotLoaded:
return "A module was not loaded."
case .invalidSubServiceID:
return "An invalid subservice ID was encountered."
case .attributeNotInContext:
return "An attribute was not in the context."
case .moduleManagerInitializeFailed:
return "A module failed to initialize."
case .moduleManagerNotFound:
return "A module was not found."
case .eventNotificationCallbackNotFound:
return "An event notification callback was not found."
case .inputLengthError:
return "An input length error was encountered."
case .outputLengthError:
return "An output length error was encountered."
case .privilegeNotSupported:
return "The privilege is not supported."
case .deviceError:
return "A device error was encountered."
case .attachHandleBusy:
return "The CSP handle was busy."
case .notLoggedIn:
return "You are not logged in."
case .algorithmMismatch:
return "An algorithm mismatch was encountered."
case .keyUsageIncorrect:
return "The key usage is incorrect."
case .keyBlobTypeIncorrect:
return "The key blob type is incorrect."
case .keyHeaderInconsistent:
return "The key header is inconsistent."
case .unsupportedKeyFormat:
return "The key header format is not supported."
case .unsupportedKeySize:
return "The key size is not supported."
case .invalidKeyUsageMask:
return "The key usage mask is not valid."
case .unsupportedKeyUsageMask:
return "The key usage mask is not supported."
case .invalidKeyAttributeMask:
return "The key attribute mask is not valid."
case .unsupportedKeyAttributeMask:
return "The key attribute mask is not supported."
case .invalidKeyLabel:
return "The key label is not valid."
case .unsupportedKeyLabel:
return "The key label is not supported."
case .invalidKeyFormat:
return "The key format is not valid."
case .unsupportedVectorOfBuffers:
return "The vector of buffers is not supported."
case .invalidInputVector:
return "The input vector is not valid."
case .invalidOutputVector:
return "The output vector is not valid."
case .invalidContext:
return "An invalid context was encountered."
case .invalidAlgorithm:
return "An invalid algorithm was encountered."
case .invalidAttributeKey:
return "A key attribute was not valid."
case .missingAttributeKey:
return "A key attribute was missing."
case .invalidAttributeInitVector:
return "An init vector attribute was not valid."
case .missingAttributeInitVector:
return "An init vector attribute was missing."
case .invalidAttributeSalt:
return "A salt attribute was not valid."
case .missingAttributeSalt:
return "A salt attribute was missing."
case .invalidAttributePadding:
return "A padding attribute was not valid."
case .missingAttributePadding:
return "A padding attribute was missing."
case .invalidAttributeRandom:
return "A random number attribute was not valid."
case .missingAttributeRandom:
return "A random number attribute was missing."
case .invalidAttributeSeed:
return "A seed attribute was not valid."
case .missingAttributeSeed:
return "A seed attribute was missing."
case .invalidAttributePassphrase:
return "A passphrase attribute was not valid."
case .missingAttributePassphrase:
return "A passphrase attribute was missing."
case .invalidAttributeKeyLength:
return "A key length attribute was not valid."
case .missingAttributeKeyLength:
return "A key length attribute was missing."
case .invalidAttributeBlockSize:
return "A block size attribute was not valid."
case .missingAttributeBlockSize:
return "A block size attribute was missing."
case .invalidAttributeOutputSize:
return "An output size attribute was not valid."
case .missingAttributeOutputSize:
return "An output size attribute was missing."
case .invalidAttributeRounds:
return "The number of rounds attribute was not valid."
case .missingAttributeRounds:
return "The number of rounds attribute was missing."
case .invalidAlgorithmParms:
return "An algorithm parameters attribute was not valid."
case .missingAlgorithmParms:
return "An algorithm parameters attribute was missing."
case .invalidAttributeLabel:
return "A label attribute was not valid."
case .missingAttributeLabel:
return "A label attribute was missing."
case .invalidAttributeKeyType:
return "A key type attribute was not valid."
case .missingAttributeKeyType:
return "A key type attribute was missing."
case .invalidAttributeMode:
return "A mode attribute was not valid."
case .missingAttributeMode:
return "A mode attribute was missing."
case .invalidAttributeEffectiveBits:
return "An effective bits attribute was not valid."
case .missingAttributeEffectiveBits:
return "An effective bits attribute was missing."
case .invalidAttributeStartDate:
return "A start date attribute was not valid."
case .missingAttributeStartDate:
return "A start date attribute was missing."
case .invalidAttributeEndDate:
return "An end date attribute was not valid."
case .missingAttributeEndDate:
return "An end date attribute was missing."
case .invalidAttributeVersion:
return "A version attribute was not valid."
case .missingAttributeVersion:
return "A version attribute was missing."
case .invalidAttributePrime:
return "A prime attribute was not valid."
case .missingAttributePrime:
return "A prime attribute was missing."
case .invalidAttributeBase:
return "A base attribute was not valid."
case .missingAttributeBase:
return "A base attribute was missing."
case .invalidAttributeSubprime:
return "A subprime attribute was not valid."
case .missingAttributeSubprime:
return "A subprime attribute was missing."
case .invalidAttributeIterationCount:
return "An iteration count attribute was not valid."
case .missingAttributeIterationCount:
return "An iteration count attribute was missing."
case .invalidAttributeDLDBHandle:
return "A database handle attribute was not valid."
case .missingAttributeDLDBHandle:
return "A database handle attribute was missing."
case .invalidAttributeAccessCredentials:
return "An access credentials attribute was not valid."
case .missingAttributeAccessCredentials:
return "An access credentials attribute was missing."
case .invalidAttributePublicKeyFormat:
return "A public key format attribute was not valid."
case .missingAttributePublicKeyFormat:
return "A public key format attribute was missing."
case .invalidAttributePrivateKeyFormat:
return "A private key format attribute was not valid."
case .missingAttributePrivateKeyFormat:
return "A private key format attribute was missing."
case .invalidAttributeSymmetricKeyFormat:
return "A symmetric key format attribute was not valid."
case .missingAttributeSymmetricKeyFormat:
return "A symmetric key format attribute was missing."
case .invalidAttributeWrappedKeyFormat:
return "A wrapped key format attribute was not valid."
case .missingAttributeWrappedKeyFormat:
return "A wrapped key format attribute was missing."
case .stagedOperationInProgress:
return "A staged operation is in progress."
case .stagedOperationNotStarted:
return "A staged operation was not started."
case .verifyFailed:
return "A cryptographic verification failure has occurred."
case .querySizeUnknown:
return "The query size is unknown."
case .blockSizeMismatch:
return "A block size mismatch occurred."
case .publicKeyInconsistent:
return "The public key was inconsistent."
case .deviceVerifyFailed:
return "A device verification failure has occurred."
case .invalidLoginName:
return "An invalid login name was detected."
case .alreadyLoggedIn:
return "The user is already logged in."
case .invalidDigestAlgorithm:
return "An invalid digest algorithm was detected."
case .invalidCRLGroup:
return "An invalid CRL group was detected."
case .certificateCannotOperate:
return "The certificate cannot operate."
case .certificateExpired:
return "An expired certificate was detected."
case .certificateNotValidYet:
return "The certificate is not yet valid."
case .certificateRevoked:
return "The certificate was revoked."
case .certificateSuspended:
return "The certificate was suspended."
case .insufficientCredentials:
return "Insufficient credentials were detected."
case .invalidAction:
return "The action was not valid."
case .invalidAuthority:
return "The authority was not valid."
case .verifyActionFailed:
return "A verify action has failed."
case .invalidCertAuthority:
return "The certificate authority was not valid."
case .invaldCRLAuthority:
return "The CRL authority was not valid."
case .invalidCRLEncoding:
return "The CRL encoding was not valid."
case .invalidCRLType:
return "The CRL type was not valid."
case .invalidCRL:
return "The CRL was not valid."
case .invalidFormType:
return "The form type was not valid."
case .invalidID:
return "The ID was not valid."
case .invalidIdentifier:
return "The identifier was not valid."
case .invalidIndex:
return "The index was not valid."
case .invalidPolicyIdentifiers:
return "The policy identifiers are not valid."
case .invalidTimeString:
return "The time specified was not valid."
case .invalidReason:
return "The trust policy reason was not valid."
case .invalidRequestInputs:
return "The request inputs are not valid."
case .invalidResponseVector:
return "The response vector was not valid."
case .invalidStopOnPolicy:
return "The stop-on policy was not valid."
case .invalidTuple:
return "The tuple was not valid."
case .multipleValuesUnsupported:
return "Multiple values are not supported."
case .notTrusted:
return "The trust policy was not trusted."
case .noDefaultAuthority:
return "No default authority was detected."
case .rejectedForm:
return "The trust policy had a rejected form."
case .requestLost:
return "The request was lost."
case .requestRejected:
return "The request was rejected."
case .unsupportedAddressType:
return "The address type is not supported."
case .unsupportedService:
return "The service is not supported."
case .invalidTupleGroup:
return "The tuple group was not valid."
case .invalidBaseACLs:
return "The base ACLs are not valid."
case .invalidTupleCredendtials:
return "The tuple credentials are not valid."
case .invalidEncoding:
return "The encoding was not valid."
case .invalidValidityPeriod:
return "The validity period was not valid."
case .invalidRequestor:
return "The requestor was not valid."
case .requestDescriptor:
return "The request descriptor was not valid."
case .invalidBundleInfo:
return "The bundle information was not valid."
case .invalidCRLIndex:
return "The CRL index was not valid."
case .noFieldValues:
return "No field values were detected."
case .unsupportedFieldFormat:
return "The field format is not supported."
case .unsupportedIndexInfo:
return "The index information is not supported."
case .unsupportedLocality:
return "The locality is not supported."
case .unsupportedNumAttributes:
return "The number of attributes is not supported."
case .unsupportedNumIndexes:
return "The number of indexes is not supported."
case .unsupportedNumRecordTypes:
return "The number of record types is not supported."
case .fieldSpecifiedMultiple:
return "Too many fields were specified."
case .incompatibleFieldFormat:
return "The field format was incompatible."
case .invalidParsingModule:
return "The parsing module was not valid."
case .databaseLocked:
return "The database is locked."
case .datastoreIsOpen:
return "The data store is open."
case .missingValue:
return "A missing value was detected."
case .unsupportedQueryLimits:
return "The query limits are not supported."
case .unsupportedNumSelectionPreds:
return "The number of selection predicates is not supported."
case .unsupportedOperator:
return "The operator is not supported."
case .invalidDBLocation:
return "The database location is not valid."
case .invalidAccessRequest:
return "The access request is not valid."
case .invalidIndexInfo:
return "The index information is not valid."
case .invalidNewOwner:
return "The new owner is not valid."
case .invalidModifyMode:
return "The modify mode is not valid."
case .missingRequiredExtension:
return "A required certificate extension is missing."
case .extendedKeyUsageNotCritical:
return "The extended key usage extension was not marked critical."
case .timestampMissing:
return "A timestamp was expected but was not found."
case .timestampInvalid:
return "The timestamp was not valid."
case .timestampNotTrusted:
return "The timestamp was not trusted."
case .timestampServiceNotAvailable:
return "The timestamp service is not available."
case .timestampBadAlg:
return "An unrecognized or unsupported Algorithm Identifier in timestamp."
case .timestampBadRequest:
return "The timestamp transaction is not permitted or supported."
case .timestampBadDataFormat:
return "The timestamp data submitted has the wrong format."
case .timestampTimeNotAvailable:
return "The time source for the Timestamp Authority is not available."
case .timestampUnacceptedPolicy:
return "The requested policy is not supported by the Timestamp Authority."
case .timestampUnacceptedExtension:
return "The requested extension is not supported by the Timestamp Authority."
case .timestampAddInfoNotAvailable:
return "The additional information requested is not available."
case .timestampSystemFailure:
return "The timestamp request cannot be handled due to system failure."
case .signingTimeMissing:
return "A signing time was expected but was not found."
case .timestampRejection:
return "A timestamp transaction was rejected."
case .timestampWaiting:
return "A timestamp transaction is waiting."
case .timestampRevocationWarning:
return "A timestamp authority revocation warning was issued."
case .timestampRevocationNotification:
return "A timestamp authority revocation notification was issued."
case .unexpectedError:
return "Unexpected error has occurred."
}
}
}
extension Status: CustomNSError {
public static let errorDomain = KeychainAccessErrorDomain
public var errorCode: Int {
return Int(rawValue)
}
public var errorUserInfo: [String : Any] {
return [NSLocalizedDescriptionKey: description]
}
}
================================================
FILE: External/KeychainAccess/Lib/KeychainAccess/KeychainAccess.h
================================================
//
// KeychainAccess.h
// KeychainAccess
//
// Created by kishikawa katsumi on 2014/12/24.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
FOUNDATION_EXPORT double KeychainAccessVersionNumber;
FOUNDATION_EXPORT const unsigned char KeychainAccessVersionString[];
================================================
FILE: External/KeychainAccess/Lib/KeychainAccess.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
140F19621A49D79400B0016A /* KeychainAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 140F19611A49D79400B0016A /* KeychainAccess.h */; settings = {ATTRIBUTES = (Public, ); }; };
140F196F1A49D79500B0016A /* KeychainAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140F196E1A49D79500B0016A /* KeychainAccessTests.swift */; };
140F197B1A49D89200B0016A /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140F197A1A49D89200B0016A /* Keychain.swift */; };
142EDA851BCB505F00A32149 /* ErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */; };
142EDB041BCBB0DD00A32149 /* SharedCredentialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */; };
148F9D4A1BCB4118006EDF48 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148F9D491BCB4118006EDF48 /* EnumTests.swift */; };
14A630181D3293C700809B3F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A630171D3293C700809B3F /* AppDelegate.swift */; };
14A6301F1D3293C700809B3F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14A6301E1D3293C700809B3F /* Assets.xcassets */; };
14C3A6781D32BF9C00349459 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; };
14C3A6791D32BF9C00349459 /* KeychainAccess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
140F19691A49D79500B0016A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 140F19531A49D79400B0016A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 140F195B1A49D79400B0016A;
remoteInfo = KeychainAccess;
};
14C3A67A1D32BF9C00349459 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 140F19531A49D79400B0016A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 140F195B1A49D79400B0016A;
remoteInfo = KeychainAccess;
};
14F0C1991D32A160007DCDDB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 140F19531A49D79400B0016A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 14A630141D3293C700809B3F;
remoteInfo = TestHost;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
14C3A67C1D32BF9D00349459 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
14C3A6791D32BF9C00349459 /* KeychainAccess.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
140F195C1A49D79400B0016A /* KeychainAccess.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KeychainAccess.framework; sourceTree = BUILT_PRODUCTS_DIR; };
140F19601A49D79400B0016A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
140F19611A49D79400B0016A /* KeychainAccess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainAccess.h; sourceTree = ""; };
140F19671A49D79500B0016A /* KeychainAccessTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainAccessTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
140F196D1A49D79500B0016A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
140F196E1A49D79500B0016A /* KeychainAccessTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainAccessTests.swift; sourceTree = ""; };
140F197A1A49D89200B0016A /* Keychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; };
142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorTypeTests.swift; sourceTree = ""; };
142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedCredentialTests.swift; sourceTree = ""; };
148E44E51BF9EDCB004FFEC1 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = Configurations/Base.xcconfig; sourceTree = ""; };
148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = ""; };
148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = ""; };
148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Tests.xcconfig; path = Configurations/Tests.xcconfig; sourceTree = ""; };
148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = KeychainAccess.xcconfig; path = Configurations/KeychainAccess.xcconfig; sourceTree = ""; };
148F9D491BCB4118006EDF48 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = ""; };
14A630151D3293C700809B3F /* TestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHost.app; sourceTree = BUILT_PRODUCTS_DIR; };
14A630171D3293C700809B3F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
14A6301E1D3293C700809B3F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
14A630231D3293C700809B3F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
14F0C1961D3295C4007DCDDB /* TestHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TestHost.entitlements; sourceTree = ""; };
14F0C1981D329832007DCDDB /* TestHost.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = TestHost.xcconfig; path = Configurations/TestHost.xcconfig; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
140F19581A49D79400B0016A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
140F19641A49D79500B0016A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
14A630121D3293C700809B3F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14C3A6781D32BF9C00349459 /* KeychainAccess.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
140F19521A49D79400B0016A = {
isa = PBXGroup;
children = (
140F195E1A49D79400B0016A /* KeychainAccess */,
140F196B1A49D79500B0016A /* KeychainAccessTests */,
148E44E41BF9ED6D004FFEC1 /* Cofigurations */,
14A630161D3293C700809B3F /* TestHost */,
140F195D1A49D79400B0016A /* Products */,
);
sourceTree = "";
};
140F195D1A49D79400B0016A /* Products */ = {
isa = PBXGroup;
children = (
140F195C1A49D79400B0016A /* KeychainAccess.framework */,
140F19671A49D79500B0016A /* KeychainAccessTests.xctest */,
14A630151D3293C700809B3F /* TestHost.app */,
);
name = Products;
sourceTree = "";
};
140F195E1A49D79400B0016A /* KeychainAccess */ = {
isa = PBXGroup;
children = (
140F19611A49D79400B0016A /* KeychainAccess.h */,
140F197A1A49D89200B0016A /* Keychain.swift */,
140F195F1A49D79400B0016A /* Supporting Files */,
);
path = KeychainAccess;
sourceTree = "";
};
140F195F1A49D79400B0016A /* Supporting Files */ = {
isa = PBXGroup;
children = (
140F19601A49D79400B0016A /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
140F196B1A49D79500B0016A /* KeychainAccessTests */ = {
isa = PBXGroup;
children = (
140F196E1A49D79500B0016A /* KeychainAccessTests.swift */,
148F9D491BCB4118006EDF48 /* EnumTests.swift */,
142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */,
142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */,
140F196C1A49D79500B0016A /* Supporting Files */,
);
path = KeychainAccessTests;
sourceTree = "";
};
140F196C1A49D79500B0016A /* Supporting Files */ = {
isa = PBXGroup;
children = (
140F196D1A49D79500B0016A /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
148E44E41BF9ED6D004FFEC1 /* Cofigurations */ = {
isa = PBXGroup;
children = (
148E44E51BF9EDCB004FFEC1 /* Base.xcconfig */,
148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */,
148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */,
148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */,
148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */,
14F0C1981D329832007DCDDB /* TestHost.xcconfig */,
);
name = Cofigurations;
sourceTree = "";
};
14A630161D3293C700809B3F /* TestHost */ = {
isa = PBXGroup;
children = (
14A630171D3293C700809B3F /* AppDelegate.swift */,
14A6301E1D3293C700809B3F /* Assets.xcassets */,
14A630231D3293C700809B3F /* Info.plist */,
14F0C1961D3295C4007DCDDB /* TestHost.entitlements */,
);
path = TestHost;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
140F19591A49D79400B0016A /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
140F19621A49D79400B0016A /* KeychainAccess.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
140F195B1A49D79400B0016A /* KeychainAccess */ = {
isa = PBXNativeTarget;
buildConfigurationList = 140F19721A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccess" */;
buildPhases = (
140F19571A49D79400B0016A /* Sources */,
140F19581A49D79400B0016A /* Frameworks */,
140F19591A49D79400B0016A /* Headers */,
140F195A1A49D79400B0016A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = KeychainAccess;
productName = KeychainAccess;
productReference = 140F195C1A49D79400B0016A /* KeychainAccess.framework */;
productType = "com.apple.product-type.framework";
};
140F19661A49D79500B0016A /* KeychainAccessTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 140F19751A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccessTests" */;
buildPhases = (
140F19631A49D79500B0016A /* Sources */,
140F19641A49D79500B0016A /* Frameworks */,
140F19651A49D79500B0016A /* Resources */,
);
buildRules = (
);
dependencies = (
140F196A1A49D79500B0016A /* PBXTargetDependency */,
14F0C19A1D32A160007DCDDB /* PBXTargetDependency */,
);
name = KeychainAccessTests;
productName = KeychainAccessTests;
productReference = 140F19671A49D79500B0016A /* KeychainAccessTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
14A630141D3293C700809B3F /* TestHost */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14A630241D3293C700809B3F /* Build configuration list for PBXNativeTarget "TestHost" */;
buildPhases = (
14A630111D3293C700809B3F /* Sources */,
14A630121D3293C700809B3F /* Frameworks */,
14A630131D3293C700809B3F /* Resources */,
14C3A67C1D32BF9D00349459 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
14C3A67B1D32BF9C00349459 /* PBXTargetDependency */,
);
name = TestHost;
productName = TestHost;
productReference = 14A630151D3293C700809B3F /* TestHost.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
140F19531A49D79400B0016A /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = "kishikawa katsumi";
TargetAttributes = {
140F195B1A49D79400B0016A = {
CreatedOnToolsVersion = 6.1.1;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
140F19661A49D79500B0016A = {
CreatedOnToolsVersion = 6.1.1;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
TestTargetID = 14A62FFC1D32922C00809B3F;
};
14A630141D3293C700809B3F = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 1020;
SystemCapabilities = {
com.apple.Keychain = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = 140F19561A49D79400B0016A /* Build configuration list for PBXProject "KeychainAccess" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 140F19521A49D79400B0016A;
productRefGroup = 140F195D1A49D79400B0016A /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
140F195B1A49D79400B0016A /* KeychainAccess */,
140F19661A49D79500B0016A /* KeychainAccessTests */,
14A630141D3293C700809B3F /* TestHost */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
140F195A1A49D79400B0016A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
140F19651A49D79500B0016A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
14A630131D3293C700809B3F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A6301F1D3293C700809B3F /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
140F19571A49D79400B0016A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
140F197B1A49D89200B0016A /* Keychain.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
140F19631A49D79500B0016A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
140F196F1A49D79500B0016A /* KeychainAccessTests.swift in Sources */,
148F9D4A1BCB4118006EDF48 /* EnumTests.swift in Sources */,
142EDA851BCB505F00A32149 /* ErrorTypeTests.swift in Sources */,
142EDB041BCBB0DD00A32149 /* SharedCredentialTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14A630111D3293C700809B3F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A630181D3293C700809B3F /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
140F196A1A49D79500B0016A /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 140F195B1A49D79400B0016A /* KeychainAccess */;
targetProxy = 140F19691A49D79500B0016A /* PBXContainerItemProxy */;
};
14C3A67B1D32BF9C00349459 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 140F195B1A49D79400B0016A /* KeychainAccess */;
targetProxy = 14C3A67A1D32BF9C00349459 /* PBXContainerItemProxy */;
};
14F0C19A1D32A160007DCDDB /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 14A630141D3293C700809B3F /* TestHost */;
targetProxy = 14F0C1991D32A160007DCDDB /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
140F19701A49D79500B0016A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */;
buildSettings = {
};
name = Debug;
};
140F19711A49D79500B0016A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */;
buildSettings = {
};
name = Release;
};
140F19731A49D79500B0016A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */;
buildSettings = {
};
name = Debug;
};
140F19741A49D79500B0016A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */;
buildSettings = {
};
name = Release;
};
140F19761A49D79500B0016A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */;
buildSettings = {
};
name = Debug;
};
140F19771A49D79500B0016A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */;
buildSettings = {
};
name = Release;
};
14A630251D3293C700809B3F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14F0C1981D329832007DCDDB /* TestHost.xcconfig */;
buildSettings = {
};
name = Debug;
};
14A630261D3293C700809B3F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14F0C1981D329832007DCDDB /* TestHost.xcconfig */;
buildSettings = {
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
140F19561A49D79400B0016A /* Build configuration list for PBXProject "KeychainAccess" */ = {
isa = XCConfigurationList;
buildConfigurations = (
140F19701A49D79500B0016A /* Debug */,
140F19711A49D79500B0016A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
140F19721A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccess" */ = {
isa = XCConfigurationList;
buildConfigurations = (
140F19731A49D79500B0016A /* Debug */,
140F19741A49D79500B0016A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
140F19751A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccessTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
140F19761A49D79500B0016A /* Debug */,
140F19771A49D79500B0016A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
14A630241D3293C700809B3F /* Build configuration list for PBXNativeTarget "TestHost" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14A630251D3293C700809B3F /* Debug */,
14A630261D3293C700809B3F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 140F19531A49D79400B0016A /* Project object */;
}
================================================
FILE: External/KeychainAccess/Lib/KeychainAccess.xcodeproj/xcshareddata/xcschemes/KeychainAccess.xcscheme
================================================
================================================
FILE: External/KeychainAccess/Lib/KeychainAccess.xcodeproj/xcshareddata/xcschemes/TestHost.xcscheme
================================================
================================================
FILE: External/KeychainAccess/Lib/KeychainAccessTests/EnumTests.swift
================================================
//
// EnumTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class EnumTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testItemClass() {
do {
let itemClass = ItemClass(rawValue: kSecClassGenericPassword as String)
XCTAssertEqual(itemClass, .genericPassword)
XCTAssertEqual(itemClass?.description, "GenericPassword")
}
do {
let itemClass = ItemClass(rawValue: kSecClassInternetPassword as String)
XCTAssertEqual(itemClass, .internetPassword)
XCTAssertEqual(itemClass?.description, "InternetPassword")
}
do {
let itemClass = ItemClass(rawValue: kSecClassCertificate as String)
XCTAssertNil(itemClass)
}
do {
let itemClass = ItemClass(rawValue: kSecClassKey as String)
XCTAssertNil(itemClass)
}
do {
let itemClass = ItemClass(rawValue: kSecClassIdentity as String)
XCTAssertNil(itemClass)
}
}
func testProtocolType() {
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTP as String)
XCTAssertEqual(protocolType, .ftp)
XCTAssertEqual(protocolType?.description, "FTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPAccount as String)
XCTAssertEqual(protocolType, .ftpAccount)
XCTAssertEqual(protocolType?.description, "FTPAccount")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTP as String)
XCTAssertEqual(protocolType, .http)
XCTAssertEqual(protocolType?.description, "HTTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRC as String)
XCTAssertEqual(protocolType, .irc)
XCTAssertEqual(protocolType?.description, "IRC")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTP as String)
XCTAssertEqual(protocolType, .nntp)
XCTAssertEqual(protocolType?.description, "NNTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3 as String)
XCTAssertEqual(protocolType, .pop3)
XCTAssertEqual(protocolType?.description, "POP3")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMTP as String)
XCTAssertEqual(protocolType, .smtp)
XCTAssertEqual(protocolType?.description, "SMTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSOCKS as String)
XCTAssertEqual(protocolType, .socks)
XCTAssertEqual(protocolType?.description, "SOCKS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAP as String)
XCTAssertEqual(protocolType, .imap)
XCTAssertEqual(protocolType?.description, "IMAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAP as String)
XCTAssertEqual(protocolType, .ldap)
XCTAssertEqual(protocolType?.description, "LDAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolAppleTalk as String)
XCTAssertEqual(protocolType, .appleTalk)
XCTAssertEqual(protocolType?.description, "AppleTalk")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolAFP as String)
XCTAssertEqual(protocolType, .afp)
XCTAssertEqual(protocolType?.description, "AFP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnet as String)
XCTAssertEqual(protocolType, .telnet)
XCTAssertEqual(protocolType?.description, "Telnet")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSSH as String)
XCTAssertEqual(protocolType, .ssh)
XCTAssertEqual(protocolType?.description, "SSH")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPS as String)
XCTAssertEqual(protocolType, .ftps)
XCTAssertEqual(protocolType?.description, "FTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPS as String)
XCTAssertEqual(protocolType, .https)
XCTAssertEqual(protocolType?.description, "HTTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPProxy as String)
XCTAssertEqual(protocolType, .httpProxy)
XCTAssertEqual(protocolType?.description, "HTTPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPSProxy as String)
XCTAssertEqual(protocolType, .httpsProxy)
XCTAssertEqual(protocolType?.description, "HTTPSProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPProxy as String)
XCTAssertEqual(protocolType, .ftpProxy)
XCTAssertEqual(protocolType?.description, "FTPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMB as String)
XCTAssertEqual(protocolType, .smb)
XCTAssertEqual(protocolType?.description, "SMB")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSP as String)
XCTAssertEqual(protocolType, .rtsp)
XCTAssertEqual(protocolType?.description, "RTSP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSPProxy as String)
XCTAssertEqual(protocolType, .rtspProxy)
XCTAssertEqual(protocolType?.description, "RTSPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolDAAP as String)
XCTAssertEqual(protocolType, .daap)
XCTAssertEqual(protocolType?.description, "DAAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolEPPC as String)
XCTAssertEqual(protocolType, .eppc)
XCTAssertEqual(protocolType?.description, "EPPC")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIPP as String)
XCTAssertEqual(protocolType, .ipp)
XCTAssertEqual(protocolType?.description, "IPP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTPS as String)
XCTAssertEqual(protocolType, .nntps)
XCTAssertEqual(protocolType?.description, "NNTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAPS as String)
XCTAssertEqual(protocolType, .ldaps)
XCTAssertEqual(protocolType?.description, "LDAPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnetS as String)
XCTAssertEqual(protocolType, .telnetS)
XCTAssertEqual(protocolType?.description, "TelnetS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAPS as String)
XCTAssertEqual(protocolType, .imaps)
XCTAssertEqual(protocolType?.description, "IMAPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRCS as String)
XCTAssertEqual(protocolType, .ircs)
XCTAssertEqual(protocolType?.description, "IRCS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3S as String)
XCTAssertEqual(protocolType, .pop3S)
XCTAssertEqual(protocolType?.description, "POP3S")
}
}
func testAuthenticationType() {
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeNTLM as String)
XCTAssertEqual(authenticationType, .ntlm)
XCTAssertEqual(authenticationType?.description, "NTLM")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeMSN as String)
XCTAssertEqual(authenticationType, .msn)
XCTAssertEqual(authenticationType?.description, "MSN")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDPA as String)
XCTAssertEqual(authenticationType, .dpa)
XCTAssertEqual(authenticationType?.description, "DPA")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeRPA as String)
XCTAssertEqual(authenticationType, .rpa)
XCTAssertEqual(authenticationType?.description, "RPA")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPBasic as String)
XCTAssertEqual(authenticationType, .httpBasic)
XCTAssertEqual(authenticationType?.description, "HTTPBasic")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPDigest as String)
XCTAssertEqual(authenticationType, .httpDigest)
XCTAssertEqual(authenticationType?.description, "HTTPDigest")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTMLForm as String)
XCTAssertEqual(authenticationType, .htmlForm)
XCTAssertEqual(authenticationType?.description, "HTMLForm")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDefault as String)
XCTAssertEqual(authenticationType, .default)
XCTAssertEqual(authenticationType?.description, "Default")
}
}
func testAccessibility() {
guard #available(OSX 10.10, *) else {
return
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlocked as String)
XCTAssertEqual(accessibility, .whenUnlocked)
XCTAssertEqual(accessibility?.description, "WhenUnlocked")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlock as String)
XCTAssertEqual(accessibility, .afterFirstUnlock)
XCTAssertEqual(accessibility?.description, "AfterFirstUnlock")
}
#if !targetEnvironment(macCatalyst)
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlways as String)
XCTAssertEqual(accessibility, .always)
XCTAssertEqual(accessibility?.description, "Always")
}
#endif
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly as String)
XCTAssertEqual(accessibility, .whenPasscodeSetThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "WhenPasscodeSetThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlockedThisDeviceOnly as String)
XCTAssertEqual(accessibility, .whenUnlockedThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "WhenUnlockedThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)
XCTAssertEqual(accessibility, .afterFirstUnlockThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "AfterFirstUnlockThisDeviceOnly")
}
#if !targetEnvironment(macCatalyst)
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlwaysThisDeviceOnly as String)
XCTAssertEqual(accessibility, .alwaysThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "AlwaysThisDeviceOnly")
}
#endif
}
}
================================================
FILE: External/KeychainAccess/Lib/KeychainAccessTests/ErrorTypeTests.swift
================================================
//
// ErrorTypeTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class ErrorTypeTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testErrorType() {
do {
let status = Status(rawValue: errSecSuccess)
XCTAssertEqual(status, .success)
XCTAssertEqual(status?.description, "No error.")
}
do {
let status = Status(rawValue: errSecUnimplemented)
XCTAssertEqual(status, .unimplemented)
XCTAssertEqual(status?.description, "Function or operation not implemented.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecDiskFull)
XCTAssertEqual(status, .diskFull)
XCTAssertEqual(status?.description, "The disk is full.")
}
#endif
do {
let status = Status(rawValue: errSecIO)
XCTAssertEqual(status, .io)
XCTAssertEqual(status?.description, "I/O error (bummers)")
}
#if os(iOS)
do {
let status = Status(rawValue: errSecOpWr)
XCTAssertEqual(status, .opWr)
XCTAssertEqual(status?.description, "file already open with with write permission")
}
#endif
do {
let status = Status(rawValue: errSecParam)
XCTAssertEqual(status, .param)
XCTAssertEqual(status?.description, "One or more parameters passed to a function were not valid.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecWrPerm)
XCTAssertEqual(status, .wrPerm)
XCTAssertEqual(status?.description, "write permissions error")
}
#endif
do {
let status = Status(rawValue: errSecAllocate)
XCTAssertEqual(status, .allocate)
XCTAssertEqual(status?.description, "Failed to allocate memory.")
}
do {
let status = Status(rawValue: errSecUserCanceled)
XCTAssertEqual(status, .userCanceled)
XCTAssertEqual(status?.description, "User canceled the operation.")
}
do {
let status = Status(rawValue: errSecBadReq)
XCTAssertEqual(status, .badReq)
XCTAssertEqual(status?.description, "Bad parameter or invalid state for operation.")
}
do {
let status = Status(rawValue: errSecInternalComponent)
XCTAssertEqual(status, .internalComponent)
XCTAssertEqual(status?.description, "")
}
do {
let status = Status(rawValue: errSecNotAvailable)
XCTAssertEqual(status, .notAvailable)
XCTAssertEqual(status?.description, "No keychain is available. You may need to restart your computer.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecReadOnly)
XCTAssertEqual(status, .readOnly)
XCTAssertEqual(status?.description, "This keychain cannot be modified.")
}
#endif
do {
let status = Status(rawValue: errSecAuthFailed)
XCTAssertEqual(status, .authFailed)
XCTAssertEqual(status?.description, "The user name or passphrase you entered is not correct.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecNoSuchKeychain)
XCTAssertEqual(status, .noSuchKeychain)
XCTAssertEqual(status?.description, "The specified keychain could not be found.")
}
do {
let status = Status(rawValue: errSecInvalidKeychain)
XCTAssertEqual(status, .invalidKeychain)
XCTAssertEqual(status?.description, "The specified keychain is not a valid keychain file.")
}
do {
let status = Status(rawValue: errSecDuplicateKeychain)
XCTAssertEqual(status, .duplicateKeychain)
XCTAssertEqual(status?.description, "A keychain with the same name already exists.")
}
do {
let status = Status(rawValue: errSecDuplicateCallback)
XCTAssertEqual(status, .duplicateCallback)
XCTAssertEqual(status?.description, "The specified callback function is already installed.")
}
do {
let status = Status(rawValue: errSecInvalidCallback)
XCTAssertEqual(status, .invalidCallback)
XCTAssertEqual(status?.description, "The specified callback function is not valid.")
}
#endif
do {
let status = Status(rawValue: errSecDuplicateItem)
XCTAssertEqual(status, .duplicateItem)
XCTAssertEqual(status?.description, "The specified item already exists in the keychain.")
}
do {
let status = Status(rawValue: errSecItemNotFound)
XCTAssertEqual(status, .itemNotFound)
XCTAssertEqual(status?.description, "The specified item could not be found in the keychain.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecBufferTooSmall)
XCTAssertEqual(status, .bufferTooSmall)
XCTAssertEqual(status?.description, "There is not enough memory available to use the specified item.")
}
do {
let status = Status(rawValue: errSecDataTooLarge)
XCTAssertEqual(status, .dataTooLarge)
XCTAssertEqual(status?.description, "This item contains information which is too large or in a format that cannot be displayed.")
}
do {
let status = Status(rawValue: errSecNoSuchAttr)
XCTAssertEqual(status, .noSuchAttr)
XCTAssertEqual(status?.description, "The specified attribute does not exist.")
}
do {
let status = Status(rawValue: errSecInvalidItemRef)
XCTAssertEqual(status, .invalidItemRef)
XCTAssertEqual(status?.description, "The specified item is no longer valid. It may have been deleted from the keychain.")
}
do {
let status = Status(rawValue: errSecInvalidSearchRef)
XCTAssertEqual(status, .invalidSearchRef)
XCTAssertEqual(status?.description, "Unable to search the current keychain.")
}
do {
let status = Status(rawValue: errSecNoSuchClass)
XCTAssertEqual(status, .noSuchClass)
XCTAssertEqual(status?.description, "The specified item does not appear to be a valid keychain item.")
}
do {
let status = Status(rawValue: errSecNoDefaultKeychain)
XCTAssertEqual(status, .noDefaultKeychain)
XCTAssertEqual(status?.description, "A default keychain could not be found.")
}
#endif
do {
let status = Status(rawValue: errSecInteractionNotAllowed)
XCTAssertEqual(status, .interactionNotAllowed)
XCTAssertEqual(status?.description, "User interaction is not allowed.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecReadOnlyAttr)
XCTAssertEqual(status, .readOnlyAttr)
XCTAssertEqual(status?.description, "The specified attribute could not be modified.")
}
do {
let status = Status(rawValue: errSecWrongSecVersion)
XCTAssertEqual(status, .wrongSecVersion)
XCTAssertEqual(status?.description, "This keychain was created by a different version of the system software and cannot be opened.")
}
do {
let status = Status(rawValue: errSecKeySizeNotAllowed)
XCTAssertEqual(status, .keySizeNotAllowed)
XCTAssertEqual(status?.description, "This item specifies a key size which is too large.")
}
do {
let status = Status(rawValue: errSecNoStorageModule)
XCTAssertEqual(status, .noStorageModule)
XCTAssertEqual(status?.description, "A required component (data storage module) could not be loaded. You may need to restart your computer.")
}
do {
let status = Status(rawValue: errSecNoCertificateModule)
XCTAssertEqual(status, .noCertificateModule)
XCTAssertEqual(status?.description, "A required component (certificate module) could not be loaded. You may need to restart your computer.")
}
do {
let status = Status(rawValue: errSecNoPolicyModule)
XCTAssertEqual(status, .noPolicyModule)
XCTAssertEqual(status?.description, "A required component (policy module) could not be loaded. You may need to restart your computer.")
}
do {
let status = Status(rawValue: errSecInteractionRequired)
XCTAssertEqual(status, .interactionRequired)
XCTAssertEqual(status?.description, "User interaction is required, but is currently not allowed.")
}
do {
let status = Status(rawValue: errSecDataNotAvailable)
XCTAssertEqual(status, .dataNotAvailable)
XCTAssertEqual(status?.description, "The contents of this item cannot be retrieved.")
}
do {
let status = Status(rawValue: errSecDataNotModifiable)
XCTAssertEqual(status, .dataNotModifiable)
XCTAssertEqual(status?.description, "The contents of this item cannot be modified.")
}
do {
let status = Status(rawValue: errSecCreateChainFailed)
XCTAssertEqual(status, .createChainFailed)
XCTAssertEqual(status?.description, "One or more certificates required to validate this certificate cannot be found.")
}
do {
let status = Status(rawValue: errSecInvalidPrefsDomain)
XCTAssertEqual(status, .invalidPrefsDomain)
XCTAssertEqual(status?.description, "The specified preferences domain is not valid.")
}
do {
let status = Status(rawValue: errSecInDarkWake)
XCTAssertEqual(status, .inDarkWake)
XCTAssertEqual(status?.description, "In dark wake, no UI possible")
}
do {
let status = Status(rawValue: errSecACLNotSimple)
XCTAssertEqual(status, .aclNotSimple)
XCTAssertEqual(status?.description, "The specified access control list is not in standard (simple) form.")
}
do {
let status = Status(rawValue: errSecPolicyNotFound)
XCTAssertEqual(status, .policyNotFound)
XCTAssertEqual(status?.description, "The specified policy cannot be found.")
}
do {
let status = Status(rawValue: errSecInvalidTrustSetting)
XCTAssertEqual(status, .invalidTrustSetting)
XCTAssertEqual(status?.description, "The specified trust setting is invalid.")
}
do {
let status = Status(rawValue: errSecNoAccessForItem)
XCTAssertEqual(status, .noAccessForItem)
XCTAssertEqual(status?.description, "The specified item has no access control.")
}
do {
let status = Status(rawValue: errSecInvalidOwnerEdit)
XCTAssertEqual(status, .invalidOwnerEdit)
XCTAssertEqual(status?.description, "Invalid attempt to change the owner of this item.")
}
do {
let status = Status(rawValue: errSecTrustNotAvailable)
XCTAssertEqual(status, .trustNotAvailable)
XCTAssertEqual(status?.description, "No trust results are available.")
}
do {
let status = Status(rawValue: errSecUnsupportedFormat)
XCTAssertEqual(status, .unsupportedFormat)
XCTAssertEqual(status?.description, "Import/Export format unsupported.")
}
do {
let status = Status(rawValue: errSecUnknownFormat)
XCTAssertEqual(status, .unknownFormat)
XCTAssertEqual(status?.description, "Unknown format in import.")
}
do {
let status = Status(rawValue: errSecKeyIsSensitive)
XCTAssertEqual(status, .keyIsSensitive)
XCTAssertEqual(status?.description, "Key material must be wrapped for export.")
}
do {
let status = Status(rawValue: errSecMultiplePrivKeys)
XCTAssertEqual(status, .multiplePrivKeys)
XCTAssertEqual(status?.description, "An attempt was made to import multiple private keys.")
}
do {
let status = Status(rawValue: errSecPassphraseRequired)
XCTAssertEqual(status, .passphraseRequired)
XCTAssertEqual(status?.description, "Passphrase is required for import/export.")
}
do {
let status = Status(rawValue: errSecInvalidPasswordRef)
XCTAssertEqual(status, .invalidPasswordRef)
XCTAssertEqual(status?.description, "The password reference was invalid.")
}
do {
let status = Status(rawValue: errSecInvalidTrustSettings)
XCTAssertEqual(status, .invalidTrustSettings)
XCTAssertEqual(status?.description, "The Trust Settings Record was corrupted.")
}
do {
let status = Status(rawValue: errSecNoTrustSettings)
XCTAssertEqual(status, .noTrustSettings)
XCTAssertEqual(status?.description, "No Trust Settings were found.")
}
do {
let status = Status(rawValue: errSecPkcs12VerifyFailure)
XCTAssertEqual(status, .pkcs12VerifyFailure)
XCTAssertEqual(status?.description, "MAC verification failed during PKCS12 import (wrong password?)")
}
do {
let errSecInvalidCertificate: OSStatus = -26265
let status = Status(rawValue: errSecInvalidCertificate)
XCTAssertEqual(status, .invalidCertificate)
XCTAssertEqual(status?.description, "This certificate could not be decoded.")
}
do {
let status = Status(rawValue: errSecNotSigner)
XCTAssertEqual(status, .notSigner)
XCTAssertEqual(status?.description, "A certificate was not signed by its proposed parent.")
}
do {
let errSecPolicyDenied: OSStatus = -26270
let status = Status(rawValue: errSecPolicyDenied)
XCTAssertEqual(status, .policyDenied)
XCTAssertEqual(status?.description, "The certificate chain was not trusted due to a policy not accepting it.")
}
do {
let errSecInvalidKey: OSStatus = -26274
let status = Status(rawValue: errSecInvalidKey)
XCTAssertEqual(status, .invalidKey)
XCTAssertEqual(status?.description, "The provided key material was not valid.")
}
#endif
do {
let status = Status(rawValue: errSecDecode)
XCTAssertEqual(status, .decode)
XCTAssertEqual(status?.description, "Unable to decode the provided data.")
}
do {
let errSecInternal: OSStatus = -26276
let status = Status(rawValue: errSecInternal)
XCTAssertEqual(status, .internal)
XCTAssertEqual(status?.description, "An internal error occurred in the Security framework.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecServiceNotAvailable)
XCTAssertEqual(status, .serviceNotAvailable)
XCTAssertEqual(status?.description, "The required service is not available.")
}
do {
let errSecUnsupportedAlgorithm: OSStatus = -26268
let status = Status(rawValue: errSecUnsupportedAlgorithm)
XCTAssertEqual(status, .unsupportedAlgorithm)
XCTAssertEqual(status?.description, "An unsupported algorithm was encountered.")
}
do {
let errSecUnsupportedOperation: OSStatus = -26271
let status = Status(rawValue: errSecUnsupportedOperation)
XCTAssertEqual(status, .unsupportedOperation)
XCTAssertEqual(status?.description, "The operation you requested is not supported by this key.")
}
do {
let errSecUnsupportedPadding: OSStatus = -26273
let status = Status(rawValue: errSecUnsupportedPadding)
XCTAssertEqual(status, .unsupportedPadding)
XCTAssertEqual(status?.description, "The padding you requested is not supported.")
}
do {
let errSecItemInvalidKey: OSStatus = -34000
let status = Status(rawValue: errSecItemInvalidKey)
XCTAssertEqual(status, .itemInvalidKey)
XCTAssertEqual(status?.description, "A string key in dictionary is not one of the supported keys.")
}
do {
let errSecItemInvalidKeyType: OSStatus = -34001
let status = Status(rawValue: errSecItemInvalidKeyType)
XCTAssertEqual(status, .itemInvalidKeyType)
XCTAssertEqual(status?.description, "A key in a dictionary is neither a CFStringRef nor a CFNumberRef.")
}
do {
let errSecItemInvalidValue: OSStatus = -34002
let status = Status(rawValue: errSecItemInvalidValue)
XCTAssertEqual(status, .itemInvalidValue)
XCTAssertEqual(status?.description, "A value in a dictionary is an invalid (or unsupported) CF type.")
}
do {
let errSecItemClassMissing: OSStatus = -34003
let status = Status(rawValue: errSecItemClassMissing)
XCTAssertEqual(status, .itemClassMissing)
XCTAssertEqual(status?.description, "No kSecItemClass key was specified in a dictionary.")
}
do {
let errSecItemMatchUnsupported: OSStatus = -34004
let status = Status(rawValue: errSecItemMatchUnsupported)
XCTAssertEqual(status, .itemMatchUnsupported)
XCTAssertEqual(status?.description, "The caller passed one or more kSecMatch keys to a function which does not support matches.")
}
do {
let errSecUseItemListUnsupported: OSStatus = -34005
let status = Status(rawValue: errSecUseItemListUnsupported)
XCTAssertEqual(status, .useItemListUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecUseItemList key to a function which does not support it.")
}
do {
let errSecUseKeychainUnsupported: OSStatus = -34006
let status = Status(rawValue: errSecUseKeychainUnsupported)
XCTAssertEqual(status, .useKeychainUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecUseKeychain key to a function which does not support it.")
}
do {
let errSecUseKeychainListUnsupported: OSStatus = -34007
let status = Status(rawValue: errSecUseKeychainListUnsupported)
XCTAssertEqual(status, .useKeychainListUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecUseKeychainList key to a function which does not support it.")
}
do {
let errSecReturnDataUnsupported: OSStatus = -34008
let status = Status(rawValue: errSecReturnDataUnsupported)
XCTAssertEqual(status, .returnDataUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnData key to a function which does not support it.")
}
do {
let errSecReturnAttributesUnsupported: OSStatus = -34009
let status = Status(rawValue: errSecReturnAttributesUnsupported)
XCTAssertEqual(status, .returnAttributesUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnAttributes key to a function which does not support it.")
}
do {
let errSecReturnRefUnsupported: OSStatus = -34010
let status = Status(rawValue: errSecReturnRefUnsupported)
XCTAssertEqual(status, .returnRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnRef key to a function which does not support it.")
}
do {
let errSecReturnPersitentRefUnsupported: OSStatus = -34011
let status = Status(rawValue: errSecReturnPersitentRefUnsupported)
XCTAssertEqual(status, .returnPersitentRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnPersistentRef key to a function which does not support it.")
}
do {
let errSecValueRefUnsupported: OSStatus = -34012
let status = Status(rawValue: errSecValueRefUnsupported)
XCTAssertEqual(status, .valueRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecValueRef key to a function which does not support it.")
}
do {
let errSecValuePersistentRefUnsupported: OSStatus = -34013
let status = Status(rawValue: errSecValuePersistentRefUnsupported)
XCTAssertEqual(status, .valuePersistentRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecValuePersistentRef key to a function which does not support it.")
}
do {
let errSecReturnMissingPointer: OSStatus = -34014
let status = Status(rawValue: errSecReturnMissingPointer)
XCTAssertEqual(status, .returnMissingPointer)
XCTAssertEqual(status?.description, "The caller passed asked for something to be returned but did not pass in a result pointer.")
}
do {
let errSecMatchLimitUnsupported: OSStatus = -34015
let status = Status(rawValue: errSecMatchLimitUnsupported)
XCTAssertEqual(status, .matchLimitUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecMatchLimit key to a call which does not support limits.")
}
do {
let errSecItemIllegalQuery: OSStatus = -34016
let status = Status(rawValue: errSecItemIllegalQuery)
XCTAssertEqual(status, .itemIllegalQuery)
XCTAssertEqual(status?.description, "The caller passed in a query which contained too many keys.")
}
do {
let errSecWaitForCallback: OSStatus = -34017
let status = Status(rawValue: errSecWaitForCallback)
XCTAssertEqual(status, .waitForCallback)
XCTAssertEqual(status?.description, "This operation is incomplete, until the callback is invoked (not an error).")
}
do {
let errSecMissingEntitlement: OSStatus = -34018
let status = Status(rawValue: errSecMissingEntitlement)
XCTAssertEqual(status, .missingEntitlement)
XCTAssertEqual(status?.description, "Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements.")
}
do {
let errSecUpgradePending: OSStatus = -34019
let status = Status(rawValue: errSecUpgradePending)
XCTAssertEqual(status, .upgradePending)
XCTAssertEqual(status?.description, "Error returned if keychain database needs a schema migration but the device is locked, clients should wait for a device unlock notification and retry the command.")
}
do {
let errSecMPSignatureInvalid: OSStatus = -25327
let status = Status(rawValue: errSecMPSignatureInvalid)
XCTAssertEqual(status, .mpSignatureInvalid)
XCTAssertEqual(status?.description, "Signature invalid on MP message")
}
do {
let errSecOTRTooOld: OSStatus = -25328
let status = Status(rawValue: errSecOTRTooOld)
XCTAssertEqual(status, .otrTooOld)
XCTAssertEqual(status?.description, "Message is too old to use")
}
do {
let errSecOTRIDTooNew: OSStatus = -25329
let status = Status(rawValue: errSecOTRIDTooNew)
XCTAssertEqual(status, .otrIDTooNew)
XCTAssertEqual(status?.description, "Key ID is too new to use! Message from the future?")
}
do {
let status = Status(rawValue: errSecInsufficientClientID)
XCTAssertEqual(status, .insufficientClientID)
XCTAssertEqual(status?.description, "The client ID is not correct.")
}
do {
let status = Status(rawValue: errSecDeviceReset)
XCTAssertEqual(status, .deviceReset)
XCTAssertEqual(status?.description, "A device reset has occurred.")
}
do {
let status = Status(rawValue: errSecDeviceFailed)
XCTAssertEqual(status, .deviceFailed)
XCTAssertEqual(status?.description, "A device failure has occurred.")
}
do {
let status = Status(rawValue: errSecAppleAddAppACLSubject)
XCTAssertEqual(status, .appleAddAppACLSubject)
XCTAssertEqual(status?.description, "Adding an application ACL subject failed.")
}
do {
let status = Status(rawValue: errSecApplePublicKeyIncomplete)
XCTAssertEqual(status, .applePublicKeyIncomplete)
XCTAssertEqual(status?.description, "The public key is incomplete.")
}
do {
let status = Status(rawValue: errSecAppleSignatureMismatch)
XCTAssertEqual(status, .appleSignatureMismatch)
XCTAssertEqual(status?.description, "A signature mismatch has occurred.")
}
do {
let status = Status(rawValue: errSecAppleInvalidKeyStartDate)
XCTAssertEqual(status, .appleInvalidKeyStartDate)
XCTAssertEqual(status?.description, "The specified key has an invalid start date.")
}
do {
let status = Status(rawValue: errSecAppleInvalidKeyEndDate)
XCTAssertEqual(status, .appleInvalidKeyEndDate)
XCTAssertEqual(status?.description, "The specified key has an invalid end date.")
}
do {
let status = Status(rawValue: errSecConversionError)
XCTAssertEqual(status, .conversionError)
XCTAssertEqual(status?.description, "A conversion error has occurred.")
}
do {
let status = Status(rawValue: errSecAppleSSLv2Rollback)
XCTAssertEqual(status, .appleSSLv2Rollback)
XCTAssertEqual(status?.description, "A SSLv2 rollback error has occurred.")
}
do {
let status = Status(rawValue: errSecDiskFull)
XCTAssertEqual(status, .diskFull)
XCTAssertEqual(status?.description, "The disk is full.")
}
do {
let status = Status(rawValue: errSecQuotaExceeded)
XCTAssertEqual(status, .quotaExceeded)
XCTAssertEqual(status?.description, "The quota was exceeded.")
}
do {
let status = Status(rawValue: errSecFileTooBig)
XCTAssertEqual(status, .fileTooBig)
XCTAssertEqual(status?.description, "The file is too big.")
}
do {
let status = Status(rawValue: errSecInvalidDatabaseBlob)
XCTAssertEqual(status, .invalidDatabaseBlob)
XCTAssertEqual(status?.description, "The specified database has an invalid blob.")
}
do {
let status = Status(rawValue: errSecInvalidKeyBlob)
XCTAssertEqual(status, .invalidKeyBlob)
XCTAssertEqual(status?.description, "The specified database has an invalid key blob.")
}
do {
let status = Status(rawValue: errSecIncompatibleDatabaseBlob)
XCTAssertEqual(status, .incompatibleDatabaseBlob)
XCTAssertEqual(status?.description, "The specified database has an incompatible blob.")
}
do {
let status = Status(rawValue: errSecIncompatibleKeyBlob)
XCTAssertEqual(status, .incompatibleKeyBlob)
XCTAssertEqual(status?.description, "The specified database has an incompatible key blob.")
}
do {
let status = Status(rawValue: errSecHostNameMismatch)
XCTAssertEqual(status, .hostNameMismatch)
XCTAssertEqual(status?.description, "A host name mismatch has occurred.")
}
do {
let status = Status(rawValue: errSecUnknownCriticalExtensionFlag)
XCTAssertEqual(status, .unknownCriticalExtensionFlag)
XCTAssertEqual(status?.description, "There is an unknown critical extension flag.")
}
do {
let status = Status(rawValue: errSecNoBasicConstraints)
XCTAssertEqual(status, .noBasicConstraints)
XCTAssertEqual(status?.description, "No basic constraints were found.")
}
do {
let status = Status(rawValue: errSecNoBasicConstraintsCA)
XCTAssertEqual(status, .noBasicConstraintsCA)
XCTAssertEqual(status?.description, "No basic CA constraints were found.")
}
do {
let status = Status(rawValue: errSecInvalidAuthorityKeyID)
XCTAssertEqual(status, .invalidAuthorityKeyID)
XCTAssertEqual(status?.description, "The authority key ID is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidSubjectKeyID)
XCTAssertEqual(status, .invalidSubjectKeyID)
XCTAssertEqual(status?.description, "The subject key ID is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidKeyUsageForPolicy)
XCTAssertEqual(status, .invalidKeyUsageForPolicy)
XCTAssertEqual(status?.description, "The key usage is not valid for the specified policy.")
}
do {
let status = Status(rawValue: errSecInvalidExtendedKeyUsage)
XCTAssertEqual(status, .invalidExtendedKeyUsage)
XCTAssertEqual(status?.description, "The extended key usage is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIDLinkage)
XCTAssertEqual(status, .invalidIDLinkage)
XCTAssertEqual(status?.description, "The ID linkage is not valid.")
}
do {
let status = Status(rawValue: errSecPathLengthConstraintExceeded)
XCTAssertEqual(status, .pathLengthConstraintExceeded)
XCTAssertEqual(status?.description, "The path length constraint was exceeded.")
}
do {
let status = Status(rawValue: errSecInvalidRoot)
XCTAssertEqual(status, .invalidRoot)
XCTAssertEqual(status?.description, "The root or anchor certificate is not valid.")
}
do {
let status = Status(rawValue: errSecCRLExpired)
XCTAssertEqual(status, .crlExpired)
XCTAssertEqual(status?.description, "The CRL has expired.")
}
do {
let status = Status(rawValue: errSecCRLNotValidYet)
XCTAssertEqual(status, .crlNotValidYet)
XCTAssertEqual(status?.description, "The CRL is not yet valid.")
}
do {
let status = Status(rawValue: errSecCRLNotFound)
XCTAssertEqual(status, .crlNotFound)
XCTAssertEqual(status?.description, "The CRL was not found.")
}
do {
let status = Status(rawValue: errSecCRLServerDown)
XCTAssertEqual(status, .crlServerDown)
XCTAssertEqual(status?.description, "The CRL server is down.")
}
do {
let status = Status(rawValue: errSecCRLBadURI)
XCTAssertEqual(status, .crlBadURI)
XCTAssertEqual(status?.description, "The CRL has a bad Uniform Resource Identifier.")
}
do {
let status = Status(rawValue: errSecUnknownCertExtension)
XCTAssertEqual(status, .unknownCertExtension)
XCTAssertEqual(status?.description, "An unknown certificate extension was encountered.")
}
do {
let status = Status(rawValue: errSecUnknownCRLExtension)
XCTAssertEqual(status, .unknownCRLExtension)
XCTAssertEqual(status?.description, "An unknown CRL extension was encountered.")
}
do {
let status = Status(rawValue: errSecCRLNotTrusted)
XCTAssertEqual(status, .crlNotTrusted)
XCTAssertEqual(status?.description, "The CRL is not trusted.")
}
do {
let status = Status(rawValue: errSecCRLPolicyFailed)
XCTAssertEqual(status, .crlPolicyFailed)
XCTAssertEqual(status?.description, "The CRL policy failed.")
}
do {
let status = Status(rawValue: errSecIDPFailure)
XCTAssertEqual(status, .idpFailure)
XCTAssertEqual(status?.description, "The issuing distribution point was not valid.")
}
do {
let status = Status(rawValue: errSecSMIMEEmailAddressesNotFound)
XCTAssertEqual(status, .smimeEmailAddressesNotFound)
XCTAssertEqual(status?.description, "An email address mismatch was encountered.")
}
do {
let status = Status(rawValue: errSecSMIMEBadExtendedKeyUsage)
XCTAssertEqual(status, .smimeBadExtendedKeyUsage)
XCTAssertEqual(status?.description, "The appropriate extended key usage for SMIME was not found.")
}
do {
let status = Status(rawValue: errSecSMIMEBadKeyUsage)
XCTAssertEqual(status, .smimeBadKeyUsage)
XCTAssertEqual(status?.description, "The key usage is not compatible with SMIME.")
}
do {
let status = Status(rawValue: errSecSMIMEKeyUsageNotCritical)
XCTAssertEqual(status, .smimeKeyUsageNotCritical)
XCTAssertEqual(status?.description, "The key usage extension is not marked as critical.")
}
do {
let status = Status(rawValue: errSecSMIMENoEmailAddress)
XCTAssertEqual(status, .smimeNoEmailAddress)
XCTAssertEqual(status?.description, "No email address was found in the certificate.")
}
do {
let status = Status(rawValue: errSecSMIMESubjAltNameNotCritical)
XCTAssertEqual(status, .smimeSubjAltNameNotCritical)
XCTAssertEqual(status?.description, "The subject alternative name extension is not marked as critical.")
}
do {
let status = Status(rawValue: errSecSSLBadExtendedKeyUsage)
XCTAssertEqual(status, .sslBadExtendedKeyUsage)
XCTAssertEqual(status?.description, "The appropriate extended key usage for SSL was not found.")
}
do {
let status = Status(rawValue: errSecOCSPBadResponse)
XCTAssertEqual(status, .ocspBadResponse)
XCTAssertEqual(status?.description, "The OCSP response was incorrect or could not be parsed.")
}
do {
let status = Status(rawValue: errSecOCSPBadRequest)
XCTAssertEqual(status, .ocspBadRequest)
XCTAssertEqual(status?.description, "The OCSP request was incorrect or could not be parsed.")
}
do {
let status = Status(rawValue: errSecOCSPUnavailable)
XCTAssertEqual(status, .ocspUnavailable)
XCTAssertEqual(status?.description, "OCSP service is unavailable.")
}
do {
let status = Status(rawValue: errSecOCSPStatusUnrecognized)
XCTAssertEqual(status, .ocspStatusUnrecognized)
XCTAssertEqual(status?.description, "The OCSP server did not recognize this certificate.")
}
do {
let status = Status(rawValue: errSecEndOfData)
XCTAssertEqual(status, .endOfData)
XCTAssertEqual(status?.description, "An end-of-data was detected.")
}
do {
let status = Status(rawValue: errSecIncompleteCertRevocationCheck)
XCTAssertEqual(status, .incompleteCertRevocationCheck)
XCTAssertEqual(status?.description, "An incomplete certificate revocation check occurred.")
}
do {
let status = Status(rawValue: errSecNetworkFailure)
XCTAssertEqual(status, .networkFailure)
XCTAssertEqual(status?.description, "A network failure occurred.")
}
do {
let status = Status(rawValue: errSecOCSPNotTrustedToAnchor)
XCTAssertEqual(status, .ocspNotTrustedToAnchor)
XCTAssertEqual(status?.description, "The OCSP response was not trusted to a root or anchor certificate.")
}
do {
let status = Status(rawValue: errSecRecordModified)
XCTAssertEqual(status, .recordModified)
XCTAssertEqual(status?.description, "The record was modified.")
}
do {
let status = Status(rawValue: errSecOCSPSignatureError)
XCTAssertEqual(status, .ocspSignatureError)
XCTAssertEqual(status?.description, "The OCSP response had an invalid signature.")
}
do {
let status = Status(rawValue: errSecOCSPNoSigner)
XCTAssertEqual(status, .ocspNoSigner)
XCTAssertEqual(status?.description, "The OCSP response had no signer.")
}
do {
let status = Status(rawValue: errSecOCSPResponderMalformedReq)
XCTAssertEqual(status, .ocspResponderMalformedReq)
XCTAssertEqual(status?.description, "The OCSP responder was given a malformed request.")
}
do {
let status = Status(rawValue: errSecOCSPResponderInternalError)
XCTAssertEqual(status, .ocspResponderInternalError)
XCTAssertEqual(status?.description, "The OCSP responder encountered an internal error.")
}
do {
let status = Status(rawValue: errSecOCSPResponderTryLater)
XCTAssertEqual(status, .ocspResponderTryLater)
XCTAssertEqual(status?.description, "The OCSP responder is busy, try again later.")
}
do {
let status = Status(rawValue: errSecOCSPResponderSignatureRequired)
XCTAssertEqual(status, .ocspResponderSignatureRequired)
XCTAssertEqual(status?.description, "The OCSP responder requires a signature.")
}
do {
let status = Status(rawValue: errSecOCSPResponderUnauthorized)
XCTAssertEqual(status, .ocspResponderUnauthorized)
XCTAssertEqual(status?.description, "The OCSP responder rejected this request as unauthorized.")
}
do {
let status = Status(rawValue: errSecOCSPResponseNonceMismatch)
XCTAssertEqual(status, .ocspResponseNonceMismatch)
XCTAssertEqual(status?.description, "The OCSP response nonce did not match the request.")
}
do {
let status = Status(rawValue: errSecCodeSigningBadCertChainLength)
XCTAssertEqual(status, .codeSigningBadCertChainLength)
XCTAssertEqual(status?.description, "Code signing encountered an incorrect certificate chain length.")
}
do {
let status = Status(rawValue: errSecCodeSigningNoBasicConstraints)
XCTAssertEqual(status, .codeSigningNoBasicConstraints)
XCTAssertEqual(status?.description, "Code signing found no basic constraints.")
}
do {
let status = Status(rawValue: errSecCodeSigningBadPathLengthConstraint)
XCTAssertEqual(status, .codeSigningBadPathLengthConstraint)
XCTAssertEqual(status?.description, "Code signing encountered an incorrect path length constraint.")
}
do {
let status = Status(rawValue: errSecCodeSigningNoExtendedKeyUsage)
XCTAssertEqual(status, .codeSigningNoExtendedKeyUsage)
XCTAssertEqual(status?.description, "Code signing found no extended key usage.")
}
do {
let status = Status(rawValue: errSecCodeSigningDevelopment)
XCTAssertEqual(status, .codeSigningDevelopment)
XCTAssertEqual(status?.description, "Code signing indicated use of a development-only certificate.")
}
do {
let status = Status(rawValue: errSecResourceSignBadCertChainLength)
XCTAssertEqual(status, .resourceSignBadCertChainLength)
XCTAssertEqual(status?.description, "Resource signing has encountered an incorrect certificate chain length.")
}
do {
let status = Status(rawValue: errSecResourceSignBadExtKeyUsage)
XCTAssertEqual(status, .resourceSignBadExtKeyUsage)
XCTAssertEqual(status?.description, "Resource signing has encountered an error in the extended key usage.")
}
do {
let status = Status(rawValue: errSecTrustSettingDeny)
XCTAssertEqual(status, .trustSettingDeny)
XCTAssertEqual(status?.description, "The trust setting for this policy was set to Deny.")
}
do {
let status = Status(rawValue: errSecInvalidSubjectName)
XCTAssertEqual(status, .invalidSubjectName)
XCTAssertEqual(status?.description, "An invalid certificate subject name was encountered.")
}
do {
let status = Status(rawValue: errSecUnknownQualifiedCertStatement)
XCTAssertEqual(status, .unknownQualifiedCertStatement)
XCTAssertEqual(status?.description, "An unknown qualified certificate statement was encountered.")
}
do {
let status = Status(rawValue: errSecMobileMeRequestQueued)
XCTAssertEqual(status, .mobileMeRequestQueued)
XCTAssertEqual(status?.description, "The MobileMe request will be sent during the next connection.")
}
do {
let status = Status(rawValue: errSecMobileMeRequestRedirected)
XCTAssertEqual(status, .mobileMeRequestRedirected)
XCTAssertEqual(status?.description, "The MobileMe request was redirected.")
}
do {
let status = Status(rawValue: errSecMobileMeServerError)
XCTAssertEqual(status, .mobileMeServerError)
XCTAssertEqual(status?.description, "A MobileMe server error occurred.")
}
do {
let status = Status(rawValue: errSecMobileMeServerNotAvailable)
XCTAssertEqual(status, .mobileMeServerNotAvailable)
XCTAssertEqual(status?.description, "The MobileMe server is not available.")
}
do {
let status = Status(rawValue: errSecMobileMeServerAlreadyExists)
XCTAssertEqual(status, .mobileMeServerAlreadyExists)
XCTAssertEqual(status?.description, "The MobileMe server reported that the item already exists.")
}
do {
let status = Status(rawValue: errSecMobileMeServerServiceErr)
XCTAssertEqual(status, .mobileMeServerServiceErr)
XCTAssertEqual(status?.description, "A MobileMe service error has occurred.")
}
do {
let status = Status(rawValue: errSecMobileMeRequestAlreadyPending)
XCTAssertEqual(status, .mobileMeRequestAlreadyPending)
XCTAssertEqual(status?.description, "A MobileMe request is already pending.")
}
do {
let status = Status(rawValue: errSecMobileMeNoRequestPending)
XCTAssertEqual(status, .mobileMeNoRequestPending)
XCTAssertEqual(status?.description, "MobileMe has no request pending.")
}
do {
let status = Status(rawValue: errSecMobileMeCSRVerifyFailure)
XCTAssertEqual(status, .mobileMeCSRVerifyFailure)
XCTAssertEqual(status?.description, "A MobileMe CSR verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecMobileMeFailedConsistencyCheck)
XCTAssertEqual(status, .mobileMeFailedConsistencyCheck)
XCTAssertEqual(status?.description, "MobileMe has found a failed consistency check.")
}
do {
let status = Status(rawValue: errSecNotInitialized)
XCTAssertEqual(status, .notInitialized)
XCTAssertEqual(status?.description, "A function was called without initializing CSSM.")
}
do {
let status = Status(rawValue: errSecInvalidHandleUsage)
XCTAssertEqual(status, .invalidHandleUsage)
XCTAssertEqual(status?.description, "The CSSM handle does not match with the service type.")
}
do {
let status = Status(rawValue: errSecPVCReferentNotFound)
XCTAssertEqual(status, .pvcReferentNotFound)
XCTAssertEqual(status?.description, "A reference to the calling module was not found in the list of authorized callers.")
}
do {
let status = Status(rawValue: errSecFunctionIntegrityFail)
XCTAssertEqual(status, .functionIntegrityFail)
XCTAssertEqual(status?.description, "A function address was not within the verified module.")
}
do {
let status = Status(rawValue: errSecInternalError)
XCTAssertEqual(status, .internalError)
XCTAssertEqual(status?.description, "An internal error has occurred.")
}
do {
let status = Status(rawValue: errSecMemoryError)
XCTAssertEqual(status, .memoryError)
XCTAssertEqual(status?.description, "A memory error has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidData)
XCTAssertEqual(status, .invalidData)
XCTAssertEqual(status?.description, "Invalid data was encountered.")
}
do {
let status = Status(rawValue: errSecMDSError)
XCTAssertEqual(status, .mdsError)
XCTAssertEqual(status?.description, "A Module Directory Service error has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidPointer)
XCTAssertEqual(status, .invalidPointer)
XCTAssertEqual(status?.description, "An invalid pointer was encountered.")
}
do {
let status = Status(rawValue: errSecSelfCheckFailed)
XCTAssertEqual(status, .selfCheckFailed)
XCTAssertEqual(status?.description, "Self-check has failed.")
}
do {
let status = Status(rawValue: errSecFunctionFailed)
XCTAssertEqual(status, .functionFailed)
XCTAssertEqual(status?.description, "A function has failed.")
}
do {
let status = Status(rawValue: errSecModuleManifestVerifyFailed)
XCTAssertEqual(status, .moduleManifestVerifyFailed)
XCTAssertEqual(status?.description, "A module manifest verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidGUID)
XCTAssertEqual(status, .invalidGUID)
XCTAssertEqual(status?.description, "An invalid GUID was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidHandle)
XCTAssertEqual(status, .invalidHandle)
XCTAssertEqual(status?.description, "An invalid handle was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidDBList)
XCTAssertEqual(status, .invalidDBList)
XCTAssertEqual(status?.description, "An invalid DB list was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidPassthroughID)
XCTAssertEqual(status, .invalidPassthroughID)
XCTAssertEqual(status?.description, "An invalid passthrough ID was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidNetworkAddress)
XCTAssertEqual(status, .invalidNetworkAddress)
XCTAssertEqual(status?.description, "An invalid network address was encountered.")
}
do {
let status = Status(rawValue: errSecCRLAlreadySigned)
XCTAssertEqual(status, .crlAlreadySigned)
XCTAssertEqual(status?.description, "The certificate revocation list is already signed.")
}
do {
let status = Status(rawValue: errSecInvalidNumberOfFields)
XCTAssertEqual(status, .invalidNumberOfFields)
XCTAssertEqual(status?.description, "An invalid number of fields were encountered.")
}
do {
let status = Status(rawValue: errSecVerificationFailure)
XCTAssertEqual(status, .verificationFailure)
XCTAssertEqual(status?.description, "A verification failure occurred.")
}
do {
let status = Status(rawValue: errSecUnknownTag)
XCTAssertEqual(status, .unknownTag)
XCTAssertEqual(status?.description, "An unknown tag was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidSignature)
XCTAssertEqual(status, .invalidSignature)
XCTAssertEqual(status?.description, "An invalid signature was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidName)
XCTAssertEqual(status, .invalidName)
XCTAssertEqual(status?.description, "An invalid name was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidCertificateRef)
XCTAssertEqual(status, .invalidCertificateRef)
XCTAssertEqual(status?.description, "An invalid certificate reference was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidCertificateGroup)
XCTAssertEqual(status, .invalidCertificateGroup)
XCTAssertEqual(status?.description, "An invalid certificate group was encountered.")
}
do {
let status = Status(rawValue: errSecTagNotFound)
XCTAssertEqual(status, .tagNotFound)
XCTAssertEqual(status?.description, "The specified tag was not found.")
}
do {
let status = Status(rawValue: errSecInvalidQuery)
XCTAssertEqual(status, .invalidQuery)
XCTAssertEqual(status?.description, "The specified query was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidValue)
XCTAssertEqual(status, .invalidValue)
XCTAssertEqual(status?.description, "An invalid value was detected.")
}
do {
let status = Status(rawValue: errSecCallbackFailed)
XCTAssertEqual(status, .callbackFailed)
XCTAssertEqual(status?.description, "A callback has failed.")
}
do {
let status = Status(rawValue: errSecACLDeleteFailed)
XCTAssertEqual(status, .aclDeleteFailed)
XCTAssertEqual(status?.description, "An ACL delete operation has failed.")
}
do {
let status = Status(rawValue: errSecACLReplaceFailed)
XCTAssertEqual(status, .aclReplaceFailed)
XCTAssertEqual(status?.description, "An ACL replace operation has failed.")
}
do {
let status = Status(rawValue: errSecACLAddFailed)
XCTAssertEqual(status, .aclAddFailed)
XCTAssertEqual(status?.description, "An ACL add operation has failed.")
}
do {
let status = Status(rawValue: errSecACLChangeFailed)
XCTAssertEqual(status, .aclChangeFailed)
XCTAssertEqual(status?.description, "An ACL change operation has failed.")
}
do {
let status = Status(rawValue: errSecInvalidAccessCredentials)
XCTAssertEqual(status, .invalidAccessCredentials)
XCTAssertEqual(status?.description, "Invalid access credentials were encountered.")
}
do {
let status = Status(rawValue: errSecInvalidRecord)
XCTAssertEqual(status, .invalidRecord)
XCTAssertEqual(status?.description, "An invalid record was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidACL)
XCTAssertEqual(status, .invalidACL)
XCTAssertEqual(status?.description, "An invalid ACL was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidSampleValue)
XCTAssertEqual(status, .invalidSampleValue)
XCTAssertEqual(status?.description, "An invalid sample value was encountered.")
}
do {
let status = Status(rawValue: errSecIncompatibleVersion)
XCTAssertEqual(status, .incompatibleVersion)
XCTAssertEqual(status?.description, "An incompatible version was encountered.")
}
do {
let status = Status(rawValue: errSecPrivilegeNotGranted)
XCTAssertEqual(status, .privilegeNotGranted)
XCTAssertEqual(status?.description, "The privilege was not granted.")
}
do {
let status = Status(rawValue: errSecInvalidScope)
XCTAssertEqual(status, .invalidScope)
XCTAssertEqual(status?.description, "An invalid scope was encountered.")
}
do {
let status = Status(rawValue: errSecPVCAlreadyConfigured)
XCTAssertEqual(status, .pvcAlreadyConfigured)
XCTAssertEqual(status?.description, "The PVC is already configured.")
}
do {
let status = Status(rawValue: errSecInvalidPVC)
XCTAssertEqual(status, .invalidPVC)
XCTAssertEqual(status?.description, "An invalid PVC was encountered.")
}
do {
let status = Status(rawValue: errSecEMMLoadFailed)
XCTAssertEqual(status, .emmLoadFailed)
XCTAssertEqual(status?.description, "The EMM load has failed.")
}
do {
let status = Status(rawValue: errSecEMMUnloadFailed)
XCTAssertEqual(status, .emmUnloadFailed)
XCTAssertEqual(status?.description, "The EMM unload has failed.")
}
do {
let status = Status(rawValue: errSecAddinLoadFailed)
XCTAssertEqual(status, .addinLoadFailed)
XCTAssertEqual(status?.description, "The add-in load operation has failed.")
}
do {
let status = Status(rawValue: errSecInvalidKeyRef)
XCTAssertEqual(status, .invalidKeyRef)
XCTAssertEqual(status?.description, "An invalid key was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidKeyHierarchy)
XCTAssertEqual(status, .invalidKeyHierarchy)
XCTAssertEqual(status?.description, "An invalid key hierarchy was encountered.")
}
do {
let status = Status(rawValue: errSecAddinUnloadFailed)
XCTAssertEqual(status, .addinUnloadFailed)
XCTAssertEqual(status?.description, "The add-in unload operation has failed.")
}
do {
let status = Status(rawValue: errSecLibraryReferenceNotFound)
XCTAssertEqual(status, .libraryReferenceNotFound)
XCTAssertEqual(status?.description, "A library reference was not found.")
}
do {
let status = Status(rawValue: errSecInvalidAddinFunctionTable)
XCTAssertEqual(status, .invalidAddinFunctionTable)
XCTAssertEqual(status?.description, "An invalid add-in function table was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidServiceMask)
XCTAssertEqual(status, .invalidServiceMask)
XCTAssertEqual(status?.description, "An invalid service mask was encountered.")
}
do {
let status = Status(rawValue: errSecModuleNotLoaded)
XCTAssertEqual(status, .moduleNotLoaded)
XCTAssertEqual(status?.description, "A module was not loaded.")
}
do {
let status = Status(rawValue: errSecInvalidSubServiceID)
XCTAssertEqual(status, .invalidSubServiceID)
XCTAssertEqual(status?.description, "An invalid subservice ID was encountered.")
}
do {
let status = Status(rawValue: errSecAttributeNotInContext)
XCTAssertEqual(status, .attributeNotInContext)
XCTAssertEqual(status?.description, "An attribute was not in the context.")
}
do {
let status = Status(rawValue: errSecModuleManagerInitializeFailed)
XCTAssertEqual(status, .moduleManagerInitializeFailed)
XCTAssertEqual(status?.description, "A module failed to initialize.")
}
do {
let status = Status(rawValue: errSecModuleManagerNotFound)
XCTAssertEqual(status, .moduleManagerNotFound)
XCTAssertEqual(status?.description, "A module was not found.")
}
do {
let status = Status(rawValue: errSecEventNotificationCallbackNotFound)
XCTAssertEqual(status, .eventNotificationCallbackNotFound)
XCTAssertEqual(status?.description, "An event notification callback was not found.")
}
do {
let status = Status(rawValue: errSecInputLengthError)
XCTAssertEqual(status, .inputLengthError)
XCTAssertEqual(status?.description, "An input length error was encountered.")
}
do {
let status = Status(rawValue: errSecOutputLengthError)
XCTAssertEqual(status, .outputLengthError)
XCTAssertEqual(status?.description, "An output length error was encountered.")
}
do {
let status = Status(rawValue: errSecPrivilegeNotSupported)
XCTAssertEqual(status, .privilegeNotSupported)
XCTAssertEqual(status?.description, "The privilege is not supported.")
}
do {
let status = Status(rawValue: errSecDeviceError)
XCTAssertEqual(status, .deviceError)
XCTAssertEqual(status?.description, "A device error was encountered.")
}
do {
let status = Status(rawValue: errSecAttachHandleBusy)
XCTAssertEqual(status, .attachHandleBusy)
XCTAssertEqual(status?.description, "The CSP handle was busy.")
}
do {
let status = Status(rawValue: errSecNotLoggedIn)
XCTAssertEqual(status, .notLoggedIn)
XCTAssertEqual(status?.description, "You are not logged in.")
}
do {
let status = Status(rawValue: errSecAlgorithmMismatch)
XCTAssertEqual(status, .algorithmMismatch)
XCTAssertEqual(status?.description, "An algorithm mismatch was encountered.")
}
do {
let status = Status(rawValue: errSecKeyUsageIncorrect)
XCTAssertEqual(status, .keyUsageIncorrect)
XCTAssertEqual(status?.description, "The key usage is incorrect.")
}
do {
let status = Status(rawValue: errSecKeyBlobTypeIncorrect)
XCTAssertEqual(status, .keyBlobTypeIncorrect)
XCTAssertEqual(status?.description, "The key blob type is incorrect.")
}
do {
let status = Status(rawValue: errSecKeyHeaderInconsistent)
XCTAssertEqual(status, .keyHeaderInconsistent)
XCTAssertEqual(status?.description, "The key header is inconsistent.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyFormat)
XCTAssertEqual(status, .unsupportedKeyFormat)
XCTAssertEqual(status?.description, "The key header format is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeySize)
XCTAssertEqual(status, .unsupportedKeySize)
XCTAssertEqual(status?.description, "The key size is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyUsageMask)
XCTAssertEqual(status, .invalidKeyUsageMask)
XCTAssertEqual(status?.description, "The key usage mask is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyUsageMask)
XCTAssertEqual(status, .unsupportedKeyUsageMask)
XCTAssertEqual(status?.description, "The key usage mask is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyAttributeMask)
XCTAssertEqual(status, .invalidKeyAttributeMask)
XCTAssertEqual(status?.description, "The key attribute mask is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyAttributeMask)
XCTAssertEqual(status, .unsupportedKeyAttributeMask)
XCTAssertEqual(status?.description, "The key attribute mask is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyLabel)
XCTAssertEqual(status, .invalidKeyLabel)
XCTAssertEqual(status?.description, "The key label is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyLabel)
XCTAssertEqual(status, .unsupportedKeyLabel)
XCTAssertEqual(status?.description, "The key label is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyFormat)
XCTAssertEqual(status, .invalidKeyFormat)
XCTAssertEqual(status?.description, "The key format is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedVectorOfBuffers)
XCTAssertEqual(status, .unsupportedVectorOfBuffers)
XCTAssertEqual(status?.description, "The vector of buffers is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidInputVector)
XCTAssertEqual(status, .invalidInputVector)
XCTAssertEqual(status?.description, "The input vector is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidOutputVector)
XCTAssertEqual(status, .invalidOutputVector)
XCTAssertEqual(status?.description, "The output vector is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidContext)
XCTAssertEqual(status, .invalidContext)
XCTAssertEqual(status?.description, "An invalid context was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidAlgorithm)
XCTAssertEqual(status, .invalidAlgorithm)
XCTAssertEqual(status?.description, "An invalid algorithm was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeKey)
XCTAssertEqual(status, .invalidAttributeKey)
XCTAssertEqual(status?.description, "A key attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeKey)
XCTAssertEqual(status, .missingAttributeKey)
XCTAssertEqual(status?.description, "A key attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeInitVector)
XCTAssertEqual(status, .invalidAttributeInitVector)
XCTAssertEqual(status?.description, "An init vector attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeInitVector)
XCTAssertEqual(status, .missingAttributeInitVector)
XCTAssertEqual(status?.description, "An init vector attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSalt)
XCTAssertEqual(status, .invalidAttributeSalt)
XCTAssertEqual(status?.description, "A salt attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSalt)
XCTAssertEqual(status, .missingAttributeSalt)
XCTAssertEqual(status?.description, "A salt attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePadding)
XCTAssertEqual(status, .invalidAttributePadding)
XCTAssertEqual(status?.description, "A padding attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePadding)
XCTAssertEqual(status, .missingAttributePadding)
XCTAssertEqual(status?.description, "A padding attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeRandom)
XCTAssertEqual(status, .invalidAttributeRandom)
XCTAssertEqual(status?.description, "A random number attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeRandom)
XCTAssertEqual(status, .missingAttributeRandom)
XCTAssertEqual(status?.description, "A random number attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSeed)
XCTAssertEqual(status, .invalidAttributeSeed)
XCTAssertEqual(status?.description, "A seed attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSeed)
XCTAssertEqual(status, .missingAttributeSeed)
XCTAssertEqual(status?.description, "A seed attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePassphrase)
XCTAssertEqual(status, .invalidAttributePassphrase)
XCTAssertEqual(status?.description, "A passphrase attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePassphrase)
XCTAssertEqual(status, .missingAttributePassphrase)
XCTAssertEqual(status?.description, "A passphrase attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeKeyLength)
XCTAssertEqual(status, .invalidAttributeKeyLength)
XCTAssertEqual(status?.description, "A key length attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeKeyLength)
XCTAssertEqual(status, .missingAttributeKeyLength)
XCTAssertEqual(status?.description, "A key length attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeBlockSize)
XCTAssertEqual(status, .invalidAttributeBlockSize)
XCTAssertEqual(status?.description, "A block size attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeBlockSize)
XCTAssertEqual(status, .missingAttributeBlockSize)
XCTAssertEqual(status?.description, "A block size attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeOutputSize)
XCTAssertEqual(status, .invalidAttributeOutputSize)
XCTAssertEqual(status?.description, "An output size attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeOutputSize)
XCTAssertEqual(status, .missingAttributeOutputSize)
XCTAssertEqual(status?.description, "An output size attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeRounds)
XCTAssertEqual(status, .invalidAttributeRounds)
XCTAssertEqual(status?.description, "The number of rounds attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeRounds)
XCTAssertEqual(status, .missingAttributeRounds)
XCTAssertEqual(status?.description, "The number of rounds attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAlgorithmParms)
XCTAssertEqual(status, .invalidAlgorithmParms)
XCTAssertEqual(status?.description, "An algorithm parameters attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAlgorithmParms)
XCTAssertEqual(status, .missingAlgorithmParms)
XCTAssertEqual(status?.description, "An algorithm parameters attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeLabel)
XCTAssertEqual(status, .invalidAttributeLabel)
XCTAssertEqual(status?.description, "A label attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeLabel)
XCTAssertEqual(status, .missingAttributeLabel)
XCTAssertEqual(status?.description, "A label attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeKeyType)
XCTAssertEqual(status, .invalidAttributeKeyType)
XCTAssertEqual(status?.description, "A key type attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeKeyType)
XCTAssertEqual(status, .missingAttributeKeyType)
XCTAssertEqual(status?.description, "A key type attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeMode)
XCTAssertEqual(status, .invalidAttributeMode)
XCTAssertEqual(status?.description, "A mode attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeMode)
XCTAssertEqual(status, .missingAttributeMode)
XCTAssertEqual(status?.description, "A mode attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeEffectiveBits)
XCTAssertEqual(status, .invalidAttributeEffectiveBits)
XCTAssertEqual(status?.description, "An effective bits attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeEffectiveBits)
XCTAssertEqual(status, .missingAttributeEffectiveBits)
XCTAssertEqual(status?.description, "An effective bits attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeStartDate)
XCTAssertEqual(status, .invalidAttributeStartDate)
XCTAssertEqual(status?.description, "A start date attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeStartDate)
XCTAssertEqual(status, .missingAttributeStartDate)
XCTAssertEqual(status?.description, "A start date attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeEndDate)
XCTAssertEqual(status, .invalidAttributeEndDate)
XCTAssertEqual(status?.description, "An end date attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeEndDate)
XCTAssertEqual(status, .missingAttributeEndDate)
XCTAssertEqual(status?.description, "An end date attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeVersion)
XCTAssertEqual(status, .invalidAttributeVersion)
XCTAssertEqual(status?.description, "A version attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeVersion)
XCTAssertEqual(status, .missingAttributeVersion)
XCTAssertEqual(status?.description, "A version attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePrime)
XCTAssertEqual(status, .invalidAttributePrime)
XCTAssertEqual(status?.description, "A prime attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePrime)
XCTAssertEqual(status, .missingAttributePrime)
XCTAssertEqual(status?.description, "A prime attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeBase)
XCTAssertEqual(status, .invalidAttributeBase)
XCTAssertEqual(status?.description, "A base attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeBase)
XCTAssertEqual(status, .missingAttributeBase)
XCTAssertEqual(status?.description, "A base attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSubprime)
XCTAssertEqual(status, .invalidAttributeSubprime)
XCTAssertEqual(status?.description, "A subprime attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSubprime)
XCTAssertEqual(status, .missingAttributeSubprime)
XCTAssertEqual(status?.description, "A subprime attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeIterationCount)
XCTAssertEqual(status, .invalidAttributeIterationCount)
XCTAssertEqual(status?.description, "An iteration count attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeIterationCount)
XCTAssertEqual(status, .missingAttributeIterationCount)
XCTAssertEqual(status?.description, "An iteration count attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeDLDBHandle)
XCTAssertEqual(status, .invalidAttributeDLDBHandle)
XCTAssertEqual(status?.description, "A database handle attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeDLDBHandle)
XCTAssertEqual(status, .missingAttributeDLDBHandle)
XCTAssertEqual(status?.description, "A database handle attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeAccessCredentials)
XCTAssertEqual(status, .invalidAttributeAccessCredentials)
XCTAssertEqual(status?.description, "An access credentials attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeAccessCredentials)
XCTAssertEqual(status, .missingAttributeAccessCredentials)
XCTAssertEqual(status?.description, "An access credentials attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePublicKeyFormat)
XCTAssertEqual(status, .invalidAttributePublicKeyFormat)
XCTAssertEqual(status?.description, "A public key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePublicKeyFormat)
XCTAssertEqual(status, .missingAttributePublicKeyFormat)
XCTAssertEqual(status?.description, "A public key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePrivateKeyFormat)
XCTAssertEqual(status, .invalidAttributePrivateKeyFormat)
XCTAssertEqual(status?.description, "A private key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePrivateKeyFormat)
XCTAssertEqual(status, .missingAttributePrivateKeyFormat)
XCTAssertEqual(status?.description, "A private key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSymmetricKeyFormat)
XCTAssertEqual(status, .invalidAttributeSymmetricKeyFormat)
XCTAssertEqual(status?.description, "A symmetric key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSymmetricKeyFormat)
XCTAssertEqual(status, .missingAttributeSymmetricKeyFormat)
XCTAssertEqual(status?.description, "A symmetric key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeWrappedKeyFormat)
XCTAssertEqual(status, .invalidAttributeWrappedKeyFormat)
XCTAssertEqual(status?.description, "A wrapped key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeWrappedKeyFormat)
XCTAssertEqual(status, .missingAttributeWrappedKeyFormat)
XCTAssertEqual(status?.description, "A wrapped key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecStagedOperationInProgress)
XCTAssertEqual(status, .stagedOperationInProgress)
XCTAssertEqual(status?.description, "A staged operation is in progress.")
}
do {
let status = Status(rawValue: errSecStagedOperationNotStarted)
XCTAssertEqual(status, .stagedOperationNotStarted)
XCTAssertEqual(status?.description, "A staged operation was not started.")
}
do {
let status = Status(rawValue: errSecVerifyFailed)
XCTAssertEqual(status, .verifyFailed)
XCTAssertEqual(status?.description, "A cryptographic verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecQuerySizeUnknown)
XCTAssertEqual(status, .querySizeUnknown)
XCTAssertEqual(status?.description, "The query size is unknown.")
}
do {
let status = Status(rawValue: errSecBlockSizeMismatch)
XCTAssertEqual(status, .blockSizeMismatch)
XCTAssertEqual(status?.description, "A block size mismatch occurred.")
}
do {
let status = Status(rawValue: errSecPublicKeyInconsistent)
XCTAssertEqual(status, .publicKeyInconsistent)
XCTAssertEqual(status?.description, "The public key was inconsistent.")
}
do {
let status = Status(rawValue: errSecDeviceVerifyFailed)
XCTAssertEqual(status, .deviceVerifyFailed)
XCTAssertEqual(status?.description, "A device verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidLoginName)
XCTAssertEqual(status, .invalidLoginName)
XCTAssertEqual(status?.description, "An invalid login name was detected.")
}
do {
let status = Status(rawValue: errSecAlreadyLoggedIn)
XCTAssertEqual(status, .alreadyLoggedIn)
XCTAssertEqual(status?.description, "The user is already logged in.")
}
do {
let status = Status(rawValue: errSecInvalidDigestAlgorithm)
XCTAssertEqual(status, .invalidDigestAlgorithm)
XCTAssertEqual(status?.description, "An invalid digest algorithm was detected.")
}
do {
let status = Status(rawValue: errSecInvalidCRLGroup)
XCTAssertEqual(status, .invalidCRLGroup)
XCTAssertEqual(status?.description, "An invalid CRL group was detected.")
}
do {
let status = Status(rawValue: errSecCertificateCannotOperate)
XCTAssertEqual(status, .certificateCannotOperate)
XCTAssertEqual(status?.description, "The certificate cannot operate.")
}
do {
let status = Status(rawValue: errSecCertificateExpired)
XCTAssertEqual(status, .certificateExpired)
XCTAssertEqual(status?.description, "An expired certificate was detected.")
}
do {
let status = Status(rawValue: errSecCertificateNotValidYet)
XCTAssertEqual(status, .certificateNotValidYet)
XCTAssertEqual(status?.description, "The certificate is not yet valid.")
}
do {
let status = Status(rawValue: errSecCertificateRevoked)
XCTAssertEqual(status, .certificateRevoked)
XCTAssertEqual(status?.description, "The certificate was revoked.")
}
do {
let status = Status(rawValue: errSecCertificateSuspended)
XCTAssertEqual(status, .certificateSuspended)
XCTAssertEqual(status?.description, "The certificate was suspended.")
}
do {
let status = Status(rawValue: errSecInsufficientCredentials)
XCTAssertEqual(status, .insufficientCredentials)
XCTAssertEqual(status?.description, "Insufficient credentials were detected.")
}
do {
let status = Status(rawValue: errSecInvalidAction)
XCTAssertEqual(status, .invalidAction)
XCTAssertEqual(status?.description, "The action was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidAuthority)
XCTAssertEqual(status, .invalidAuthority)
XCTAssertEqual(status?.description, "The authority was not valid.")
}
do {
let status = Status(rawValue: errSecVerifyActionFailed)
XCTAssertEqual(status, .verifyActionFailed)
XCTAssertEqual(status?.description, "A verify action has failed.")
}
do {
let status = Status(rawValue: errSecInvalidCertAuthority)
XCTAssertEqual(status, .invalidCertAuthority)
XCTAssertEqual(status?.description, "The certificate authority was not valid.")
}
do {
let status = Status(rawValue: errSecInvaldCRLAuthority)
XCTAssertEqual(status, .invaldCRLAuthority)
XCTAssertEqual(status?.description, "The CRL authority was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRLEncoding)
XCTAssertEqual(status, .invalidCRLEncoding)
XCTAssertEqual(status?.description, "The CRL encoding was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRLType)
XCTAssertEqual(status, .invalidCRLType)
XCTAssertEqual(status?.description, "The CRL type was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRL)
XCTAssertEqual(status, .invalidCRL)
XCTAssertEqual(status?.description, "The CRL was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidFormType)
XCTAssertEqual(status, .invalidFormType)
XCTAssertEqual(status?.description, "The form type was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidID)
XCTAssertEqual(status, .invalidID)
XCTAssertEqual(status?.description, "The ID was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIdentifier)
XCTAssertEqual(status, .invalidIdentifier)
XCTAssertEqual(status?.description, "The identifier was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIndex)
XCTAssertEqual(status, .invalidIndex)
XCTAssertEqual(status?.description, "The index was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidPolicyIdentifiers)
XCTAssertEqual(status, .invalidPolicyIdentifiers)
XCTAssertEqual(status?.description, "The policy identifiers are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidTimeString)
XCTAssertEqual(status, .invalidTimeString)
XCTAssertEqual(status?.description, "The time specified was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidReason)
XCTAssertEqual(status, .invalidReason)
XCTAssertEqual(status?.description, "The trust policy reason was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidRequestInputs)
XCTAssertEqual(status, .invalidRequestInputs)
XCTAssertEqual(status?.description, "The request inputs are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidResponseVector)
XCTAssertEqual(status, .invalidResponseVector)
XCTAssertEqual(status?.description, "The response vector was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidStopOnPolicy)
XCTAssertEqual(status, .invalidStopOnPolicy)
XCTAssertEqual(status?.description, "The stop-on policy was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidTuple)
XCTAssertEqual(status, .invalidTuple)
XCTAssertEqual(status?.description, "The tuple was not valid.")
}
do {
let status = Status(rawValue: errSecMultipleValuesUnsupported)
XCTAssertEqual(status, .multipleValuesUnsupported)
XCTAssertEqual(status?.description, "Multiple values are not supported.")
}
do {
let status = Status(rawValue: errSecNotTrusted)
XCTAssertEqual(status, .notTrusted)
XCTAssertEqual(status?.description, "The trust policy was not trusted.")
}
do {
let status = Status(rawValue: errSecNoDefaultAuthority)
XCTAssertEqual(status, .noDefaultAuthority)
XCTAssertEqual(status?.description, "No default authority was detected.")
}
do {
let status = Status(rawValue: errSecRejectedForm)
XCTAssertEqual(status, .rejectedForm)
XCTAssertEqual(status?.description, "The trust policy had a rejected form.")
}
do {
let status = Status(rawValue: errSecRequestLost)
XCTAssertEqual(status, .requestLost)
XCTAssertEqual(status?.description, "The request was lost.")
}
do {
let status = Status(rawValue: errSecRequestRejected)
XCTAssertEqual(status, .requestRejected)
XCTAssertEqual(status?.description, "The request was rejected.")
}
do {
let status = Status(rawValue: errSecUnsupportedAddressType)
XCTAssertEqual(status, .unsupportedAddressType)
XCTAssertEqual(status?.description, "The address type is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedService)
XCTAssertEqual(status, .unsupportedService)
XCTAssertEqual(status?.description, "The service is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidTupleGroup)
XCTAssertEqual(status, .invalidTupleGroup)
XCTAssertEqual(status?.description, "The tuple group was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidBaseACLs)
XCTAssertEqual(status, .invalidBaseACLs)
XCTAssertEqual(status?.description, "The base ACLs are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidTupleCredendtials)
XCTAssertEqual(status, .invalidTupleCredendtials)
XCTAssertEqual(status?.description, "The tuple credentials are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidEncoding)
XCTAssertEqual(status, .invalidEncoding)
XCTAssertEqual(status?.description, "The encoding was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidValidityPeriod)
XCTAssertEqual(status, .invalidValidityPeriod)
XCTAssertEqual(status?.description, "The validity period was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidRequestor)
XCTAssertEqual(status, .invalidRequestor)
XCTAssertEqual(status?.description, "The requestor was not valid.")
}
do {
let status = Status(rawValue: errSecRequestDescriptor)
XCTAssertEqual(status, .requestDescriptor)
XCTAssertEqual(status?.description, "The request descriptor was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidBundleInfo)
XCTAssertEqual(status, .invalidBundleInfo)
XCTAssertEqual(status?.description, "The bundle information was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRLIndex)
XCTAssertEqual(status, .invalidCRLIndex)
XCTAssertEqual(status?.description, "The CRL index was not valid.")
}
do {
let status = Status(rawValue: errSecNoFieldValues)
XCTAssertEqual(status, .noFieldValues)
XCTAssertEqual(status?.description, "No field values were detected.")
}
do {
let status = Status(rawValue: errSecUnsupportedFieldFormat)
XCTAssertEqual(status, .unsupportedFieldFormat)
XCTAssertEqual(status?.description, "The field format is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedIndexInfo)
XCTAssertEqual(status, .unsupportedIndexInfo)
XCTAssertEqual(status?.description, "The index information is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedLocality)
XCTAssertEqual(status, .unsupportedLocality)
XCTAssertEqual(status?.description, "The locality is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumAttributes)
XCTAssertEqual(status, .unsupportedNumAttributes)
XCTAssertEqual(status?.description, "The number of attributes is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumIndexes)
XCTAssertEqual(status, .unsupportedNumIndexes)
XCTAssertEqual(status?.description, "The number of indexes is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumRecordTypes)
XCTAssertEqual(status, .unsupportedNumRecordTypes)
XCTAssertEqual(status?.description, "The number of record types is not supported.")
}
do {
let status = Status(rawValue: errSecFieldSpecifiedMultiple)
XCTAssertEqual(status, .fieldSpecifiedMultiple)
XCTAssertEqual(status?.description, "Too many fields were specified.")
}
do {
let status = Status(rawValue: errSecIncompatibleFieldFormat)
XCTAssertEqual(status, .incompatibleFieldFormat)
XCTAssertEqual(status?.description, "The field format was incompatible.")
}
do {
let status = Status(rawValue: errSecInvalidParsingModule)
XCTAssertEqual(status, .invalidParsingModule)
XCTAssertEqual(status?.description, "The parsing module was not valid.")
}
do {
let status = Status(rawValue: errSecDatabaseLocked)
XCTAssertEqual(status, .databaseLocked)
XCTAssertEqual(status?.description, "The database is locked.")
}
do {
let status = Status(rawValue: errSecDatastoreIsOpen)
XCTAssertEqual(status, .datastoreIsOpen)
XCTAssertEqual(status?.description, "The data store is open.")
}
do {
let status = Status(rawValue: errSecMissingValue)
XCTAssertEqual(status, .missingValue)
XCTAssertEqual(status?.description, "A missing value was detected.")
}
do {
let status = Status(rawValue: errSecUnsupportedQueryLimits)
XCTAssertEqual(status, .unsupportedQueryLimits)
XCTAssertEqual(status?.description, "The query limits are not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumSelectionPreds)
XCTAssertEqual(status, .unsupportedNumSelectionPreds)
XCTAssertEqual(status?.description, "The number of selection predicates is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedOperator)
XCTAssertEqual(status, .unsupportedOperator)
XCTAssertEqual(status?.description, "The operator is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidDBLocation)
XCTAssertEqual(status, .invalidDBLocation)
XCTAssertEqual(status?.description, "The database location is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidAccessRequest)
XCTAssertEqual(status, .invalidAccessRequest)
XCTAssertEqual(status?.description, "The access request is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIndexInfo)
XCTAssertEqual(status, .invalidIndexInfo)
XCTAssertEqual(status?.description, "The index information is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidNewOwner)
XCTAssertEqual(status, .invalidNewOwner)
XCTAssertEqual(status?.description, "The new owner is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidModifyMode)
XCTAssertEqual(status, .invalidModifyMode)
XCTAssertEqual(status?.description, "The modify mode is not valid.")
}
do {
let status = Status(rawValue: errSecMissingRequiredExtension)
XCTAssertEqual(status, .missingRequiredExtension)
XCTAssertEqual(status?.description, "A required certificate extension is missing.")
}
do {
let status = Status(rawValue: errSecExtendedKeyUsageNotCritical)
XCTAssertEqual(status, .extendedKeyUsageNotCritical)
XCTAssertEqual(status?.description, "The extended key usage extension was not marked critical.")
}
do {
let status = Status(rawValue: errSecTimestampMissing)
XCTAssertEqual(status, .timestampMissing)
XCTAssertEqual(status?.description, "A timestamp was expected but was not found.")
}
do {
let status = Status(rawValue: errSecTimestampInvalid)
XCTAssertEqual(status, .timestampInvalid)
XCTAssertEqual(status?.description, "The timestamp was not valid.")
}
do {
let status = Status(rawValue: errSecTimestampNotTrusted)
XCTAssertEqual(status, .timestampNotTrusted)
XCTAssertEqual(status?.description, "The timestamp was not trusted.")
}
do {
let status = Status(rawValue: errSecTimestampServiceNotAvailable)
XCTAssertEqual(status, .timestampServiceNotAvailable)
XCTAssertEqual(status?.description, "The timestamp service is not available.")
}
do {
let status = Status(rawValue: errSecTimestampBadAlg)
XCTAssertEqual(status, .timestampBadAlg)
XCTAssertEqual(status?.description, "An unrecognized or unsupported Algorithm Identifier in timestamp.")
}
do {
let status = Status(rawValue: errSecTimestampBadRequest)
XCTAssertEqual(status, .timestampBadRequest)
XCTAssertEqual(status?.description, "The timestamp transaction is not permitted or supported.")
}
do {
let status = Status(rawValue: errSecTimestampBadDataFormat)
XCTAssertEqual(status, .timestampBadDataFormat)
XCTAssertEqual(status?.description, "The timestamp data submitted has the wrong format.")
}
do {
let status = Status(rawValue: errSecTimestampTimeNotAvailable)
XCTAssertEqual(status, .timestampTimeNotAvailable)
XCTAssertEqual(status?.description, "The time source for the Timestamp Authority is not available.")
}
do {
let status = Status(rawValue: errSecTimestampUnacceptedPolicy)
XCTAssertEqual(status, .timestampUnacceptedPolicy)
XCTAssertEqual(status?.description, "The requested policy is not supported by the Timestamp Authority.")
}
do {
let status = Status(rawValue: errSecTimestampUnacceptedExtension)
XCTAssertEqual(status, .timestampUnacceptedExtension)
XCTAssertEqual(status?.description, "The requested extension is not supported by the Timestamp Authority.")
}
do {
let status = Status(rawValue: errSecTimestampAddInfoNotAvailable)
XCTAssertEqual(status, .timestampAddInfoNotAvailable)
XCTAssertEqual(status?.description, "The additional information requested is not available.")
}
do {
let status = Status(rawValue: errSecTimestampSystemFailure)
XCTAssertEqual(status, .timestampSystemFailure)
XCTAssertEqual(status?.description, "The timestamp request cannot be handled due to system failure.")
}
do {
let status = Status(rawValue: errSecSigningTimeMissing)
XCTAssertEqual(status, .signingTimeMissing)
XCTAssertEqual(status?.description, "A signing time was expected but was not found.")
}
do {
let status = Status(rawValue: errSecTimestampRejection)
XCTAssertEqual(status, .timestampRejection)
XCTAssertEqual(status?.description, "A timestamp transaction was rejected.")
}
do {
let status = Status(rawValue: errSecTimestampWaiting)
XCTAssertEqual(status, .timestampWaiting)
XCTAssertEqual(status?.description, "A timestamp transaction is waiting.")
}
do {
let status = Status(rawValue: errSecTimestampRevocationWarning)
XCTAssertEqual(status, .timestampRevocationWarning)
XCTAssertEqual(status?.description, "A timestamp authority revocation warning was issued.")
}
do {
let status = Status(rawValue: errSecTimestampRevocationNotification)
XCTAssertEqual(status, .timestampRevocationNotification)
XCTAssertEqual(status?.description, "A timestamp authority revocation notification was issued.")
}
#endif
}
}
================================================
FILE: External/KeychainAccess/Lib/KeychainAccessTests/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
BNDL
CFBundleShortVersionString
1.0.0
CFBundleSignature
????
CFBundleVersion
1
================================================
FILE: External/KeychainAccess/Lib/KeychainAccessTests/KeychainAccessTests.swift
================================================
//
// KeychainAccessTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 2014/12/24.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import XCTest
import KeychainAccess
class KeychainAccessTests: XCTestCase {
override func setUp() {
super.setUp()
do { try Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").removeAll() } catch {}
do { try Keychain(service: "Twitter").removeAll() } catch {}
do { try Keychain(server: URL(string: "https://example.com")!, protocolType: .https).removeAll() } catch {}
do { try Keychain(server: URL(string: "https://example.com:443")!, protocolType: .https).removeAll() } catch {}
do { try Keychain().removeAll() } catch {}
}
override func tearDown() {
super.tearDown()
}
// MARK:
func testGenericPassword() {
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter")
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "kishikawa_katsumi")
let password = try! keychain.get("password")
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter")
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "katsumi_kishikawa")
let password = try! keychain.get("password")
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter")
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testGenericPasswordSubscripting() {
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
keychain["username"] = "kishikawa_katsumi"
keychain["password"] = "password_1234"
let username = keychain["username"]
XCTAssertEqual(username, "kishikawa_katsumi")
let password = keychain["password"]
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
keychain["username"] = "katsumi_kishikawa"
keychain["password"] = "1234_password"
let username = keychain["username"]
XCTAssertEqual(username, "katsumi_kishikawa")
let password = keychain["password"]
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
keychain["username"] = nil
keychain["password"] = nil
XCTAssertNil(keychain["username"])
XCTAssertNil(keychain["password"])
}
}
func testGenericPasswordWithAccessGroup1() {
do {
// Add Keychain items
// This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
// kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
// https://developer.apple.com/documentation/security/ksecattraccessgroup
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychainWithAccessGroup.remove("username") } catch {}
do { try keychainWithAccessGroup.remove("password") } catch {}
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
XCTAssertNotNil(try! keychain.get("username"))
XCTAssertNotNil(try! keychain.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testGenericPasswordWithAccessGroup2() {
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
// If the access group is empty, the query will match all access group. So delete all values in other access groups.
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
}
}
// MARK:
func testInternetPassword() {
do {
// Add Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "kishikawa_katsumi")
let password = try! keychain.get("password")
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "katsumi_kishikawa")
let password = try! keychain.get("password")
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testInternetPasswordSubscripting() {
do {
// Add Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
keychain["username"] = "kishikawa_katsumi"
keychain["password"] = "password_1234"
let username = keychain["username"]
XCTAssertEqual(username, "kishikawa_katsumi")
let password = keychain["password"]
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
keychain["username"] = "katsumi_kishikawa"
keychain["password"] = "1234_password"
let username = keychain["username"]
XCTAssertEqual(username, "katsumi_kishikawa")
let password = keychain["password"]
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
keychain["username"] = nil
keychain["password"] = nil
XCTAssertNil(keychain["username"])
XCTAssertNil(keychain["password"])
}
}
func testInternetPasswordWithAccessGroup1() {
do {
// Add Keychain items
// This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
// kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
// https://developer.apple.com/documentation/security/ksecattraccessgroup
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychainWithAccessGroup.remove("username") } catch {}
do { try keychainWithAccessGroup.remove("password") } catch {}
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
XCTAssertNotNil(try! keychain.get("username"))
XCTAssertNotNil(try! keychain.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testInternetPasswordWithAccessGroup2() {
do {
// Add Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
// If the access group is empty, the query will match all access group. So delete all values in other access groups.
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
}
}
// MARK:
func testDefaultInitializer() {
let keychain = Keychain()
XCTAssertEqual(keychain.service, Bundle.main.bundleIdentifier)
let service: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(keychain.service, service)
XCTAssertNil(keychain.accessGroup)
}
func testInitializerWithService() {
let keychain = Keychain(service: "com.example.github-token")
XCTAssertEqual(keychain.service, "com.example.github-token")
XCTAssertNil(keychain.accessGroup)
}
func testInitializerWithAccessGroup() {
let keychain = Keychain(accessGroup: "27AEDK3C9F.shared")
let service: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(keychain.service, service)
XCTAssertEqual(keychain.accessGroup, "27AEDK3C9F.shared")
}
func testInitializerWithServiceAndAccessGroup() {
let keychain = Keychain(service: "com.example.github-token", accessGroup: "27AEDK3C9F.shared")
XCTAssertEqual(keychain.service, "com.example.github-token")
XCTAssertEqual(keychain.accessGroup, "27AEDK3C9F.shared")
}
func testInitializerWithServer() {
let server = "https://kishikawakatsumi.com"
let url = URL(string: server)!
do {
let keychain = Keychain(server: server, protocolType: .https)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.default)
}
do {
let keychain = Keychain(server: url, protocolType: .https)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.default)
}
}
func testInitializerWithServerAndAuthenticationType() {
let server = "https://kishikawakatsumi.com"
let url = URL(string: server)!
do {
let keychain = Keychain(server: server, protocolType: .https, authenticationType: .htmlForm)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.htmlForm)
}
do {
let keychain = Keychain(server: url, protocolType: .https, authenticationType: .htmlForm)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.htmlForm)
}
}
// MARK:
func testContains() {
let keychain = Keychain(service: "Twitter")
XCTAssertFalse(try! keychain.contains("username"), "not stored username")
XCTAssertFalse(try! keychain.contains("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertTrue(try! keychain.contains("username"), "stored username")
XCTAssertFalse(try! keychain.contains("password"), "not stored password")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertTrue(try! keychain.contains("username"), "stored username")
XCTAssertTrue(try! keychain.contains("password"), "stored password")
}
// MARK:
func testSetString() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
}
func testSetStringWithLabel() {
let keychain = Keychain(service: "Twitter")
.label("Twitter Account")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertNil(label)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertEqual(label, "Twitter Account")
} catch {
XCTFail("error occurred")
}
}
func testSetStringWithComment() {
let keychain = Keychain(service: "Twitter")
.comment("Kishikawa Katsumi")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertNil(comment)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertEqual(comment, "Kishikawa Katsumi")
} catch {
XCTFail("error occurred")
}
}
func testSetStringWithLabelAndComment() {
let keychain = Keychain(service: "Twitter")
.label("Twitter Account")
.comment("Kishikawa Katsumi")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertNil(label)
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertNil(comment)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertEqual(label, "Twitter Account")
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertEqual(comment, "Kishikawa Katsumi")
} catch {
XCTFail("error occurred")
}
}
func testSetData() {
let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
let JSONData = try! JSONSerialization.data(withJSONObject: JSONObject, options: [])
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
do { try keychain.set(JSONData, key: "JSONData") } catch {}
XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
}
func testStringConversionError() {
let keychain = Keychain(service: "Twitter")
let length = 256
let data = NSMutableData(length: length)!
let bytes = data.mutableBytes.bindMemory(to: UInt8.self, capacity: length)
_ = SecRandomCopyBytes(kSecRandomDefault, length, bytes)
do {
try keychain.set(data as Data, key: "RandomData")
let _ = try keychain.getString("RandomData")
XCTFail("no error occurred")
} catch let error as NSError {
XCTAssertEqual(error.domain, KeychainAccessErrorDomain)
XCTAssertEqual(error.code, Int(Status.conversionError.rawValue))
XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as! String, Status.conversionError.localizedDescription)
} catch {
XCTFail("unexpected error occurred")
}
do {
try keychain.set(data as Data, key: "RandomData")
let _ = try keychain.getString("RandomData")
XCTFail("no error occurred")
} catch Status.conversionError {
XCTAssertTrue(true)
} catch {
XCTFail("unexpected error occurred")
}
}
func testGetPersistentRef() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
XCTAssertNil(persistentRef)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
XCTAssertNotNil(persistentRef)
} catch {
XCTFail("error occurred")
}
}
#if os(iOS) || os(tvOS)
func testSetAttributes() {
do {
var attributes = [String: Any]()
attributes[String(kSecAttrDescription)] = "Description Test"
attributes[String(kSecAttrComment)] = "Comment Test"
attributes[String(kSecAttrCreator)] = "Creator Test"
attributes[String(kSecAttrType)] = "Type Test"
attributes[String(kSecAttrLabel)] = "Label Test"
attributes[String(kSecAttrIsInvisible)] = true
attributes[String(kSecAttrIsNegative)] = true
let keychain = Keychain(service: "Twitter")
.attributes(attributes)
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertNil(attributes)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertEqual(attributes?.`class`, ItemClass.genericPassword.rawValue)
XCTAssertEqual(attributes?.data, "password1234".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if targetEnvironment(macCatalyst)
XCTAssertNotNil(attributes?.accessControl)
#else
if ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 11, minorVersion: 3, patchVersion: 0)) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Description Test")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertEqual(attributes?.service, "Twitter")
XCTAssertNil(attributes?.generic)
XCTAssertNil(attributes?.securityDomain)
XCTAssertNil(attributes?.server)
XCTAssertNil(attributes?.`protocol`)
XCTAssertNil(attributes?.authenticationType)
XCTAssertNil(attributes?.port)
XCTAssertNil(attributes?.path)
XCTAssertEqual(attributes?[String(kSecClass)] as? String, ItemClass.genericPassword.rawValue)
XCTAssertEqual(attributes?[String(kSecValueData)] as? Data, "password1234".data(using: .utf8))
} catch {
XCTFail("error occurred")
}
}
do {
var attributes = [String: Any]()
attributes[String(kSecAttrDescription)] = "Description Test"
attributes[String(kSecAttrComment)] = "Comment Test"
attributes[String(kSecAttrCreator)] = "Creator Test"
attributes[String(kSecAttrType)] = "Type Test"
attributes[String(kSecAttrLabel)] = "Label Test"
attributes[String(kSecAttrIsInvisible)] = true
attributes[String(kSecAttrIsNegative)] = true
attributes[String(kSecAttrSecurityDomain)] = "securitydomain"
let keychain = Keychain(server: URL(string: "https://example.com:443/api/login/")!, protocolType: .https)
.attributes(attributes)
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertNil(attributes)
} catch {
XCTFail("error occurred")
}
do {
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertEqual(attributes?.`class`, ItemClass.internetPassword.rawValue)
XCTAssertEqual(attributes?.data, "password1234".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if os(iOS)
if #available(iOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else if #available(iOS 9.0, *) {
XCTAssertNil(attributes?.accessControl)
} else {
XCTAssertNotNil(attributes?.accessControl)
}
#else
if #available(tvOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Description Test")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertNil(attributes?.service)
XCTAssertNil(attributes?.generic)
XCTAssertEqual(attributes?.securityDomain, "securitydomain")
XCTAssertEqual(attributes?.server, "example.com")
XCTAssertEqual(attributes?.`protocol`, ProtocolType.https.rawValue)
XCTAssertEqual(attributes?.authenticationType, AuthenticationType.default.rawValue)
XCTAssertEqual(attributes?.port, 443)
XCTAssertEqual(attributes?.path, "")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(server: URL(string: "https://example.com:443/api/login/")!, protocolType: .https)
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
keychain["kishikawakatsumi"] = "1234password"
XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "updated password")
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertEqual(attributes?.`class`, ItemClass.internetPassword.rawValue)
XCTAssertEqual(attributes?.data, "1234password".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if os(iOS)
if #available(iOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else if #available(iOS 9.0, *) {
XCTAssertNil(attributes?.accessControl)
} else {
XCTAssertNotNil(attributes?.accessControl)
}
#else
if #available(tvOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Description Test")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertNil(attributes?.service)
XCTAssertNil(attributes?.generic)
XCTAssertEqual(attributes?.securityDomain, "securitydomain")
XCTAssertEqual(attributes?.server, "example.com")
XCTAssertEqual(attributes?.`protocol`, ProtocolType.https.rawValue)
XCTAssertEqual(attributes?.authenticationType, AuthenticationType.default.rawValue)
XCTAssertEqual(attributes?.port, 443)
XCTAssertEqual(attributes?.path, "")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(server: URL(string: "https://example.com:443/api/login/")!, protocolType: .https)
.attributes([String(kSecAttrDescription): "Updated Description"])
XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "stored password")
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "updated password")
let attributes = keychain[attributes: "kishikawakatsumi"]
XCTAssertEqual(attributes?.`class`, ItemClass.internetPassword.rawValue)
XCTAssertEqual(attributes?.data, "password1234".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if os(iOS)
if #available(iOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else if #available(iOS 9.0, *) {
XCTAssertNil(attributes?.accessControl)
} else {
XCTAssertNotNil(attributes?.accessControl)
}
#else
if #available(tvOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Updated Description")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertNil(attributes?.service)
XCTAssertNil(attributes?.generic)
XCTAssertEqual(attributes?.securityDomain, "securitydomain")
XCTAssertEqual(attributes?.server, "example.com")
XCTAssertEqual(attributes?.`protocol`, ProtocolType.https.rawValue)
XCTAssertEqual(attributes?.authenticationType, AuthenticationType.default.rawValue)
XCTAssertEqual(attributes?.port, 443)
XCTAssertEqual(attributes?.path, "")
}
}
}
#endif
func testRemoveString() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
do { try keychain.remove("username") } catch {}
XCTAssertNil(try! keychain.get("username"), "removed username")
XCTAssertEqual(try! keychain.get("password"), "password1234", "left password")
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"), "removed username")
XCTAssertNil(try! keychain.get("password"), "removed password")
}
func testRemoveData() {
let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
let JSONData = try! JSONSerialization.data(withJSONObject: JSONObject, options: [])
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
do { try keychain.set(JSONData, key: "JSONData") } catch {}
XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
do { try keychain.remove("JSONData") } catch {}
XCTAssertNil(try! keychain.getData("JSONData"), "removed JSON data")
}
// MARK:
func testSubscripting() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(keychain["username"], "not stored username")
XCTAssertNil(keychain["password"], "not stored password")
XCTAssertNil(keychain[string: "username"], "not stored username")
XCTAssertNil(keychain[string: "password"], "not stored password")
keychain["username"] = "kishikawakatsumi"
XCTAssertEqual(keychain["username"], "kishikawakatsumi", "stored username")
XCTAssertEqual(keychain[string: "username"], "kishikawakatsumi", "stored username")
keychain["password"] = "password1234"
XCTAssertEqual(keychain["password"], "password1234", "stored password")
XCTAssertEqual(keychain[string: "password"], "password1234", "stored password")
keychain[string: "username"] = nil
XCTAssertNil(keychain["username"], "removed username")
XCTAssertEqual(keychain["password"], "password1234", "left password")
XCTAssertNil(keychain[string: "username"], "removed username")
XCTAssertEqual(keychain[string: "password"], "password1234", "left password")
keychain[string: "password"] = nil
XCTAssertNil(keychain["username"], "removed username")
XCTAssertNil(keychain["password"], "removed password")
XCTAssertNil(keychain[string: "username"], "removed username")
XCTAssertNil(keychain[string: "password"], "removed password")
let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
let JSONData = try! JSONSerialization.data(withJSONObject: JSONObject, options: [])
XCTAssertNil(keychain[data:"JSONData"], "not stored JSON data")
keychain[data: "JSONData"] = JSONData
XCTAssertEqual(keychain[data: "JSONData"], JSONData, "stored JSON data")
keychain[data: "JSONData"] = nil
XCTAssertNil(keychain[data:"JSONData"], "removed JSON data")
}
// MARK:
func testErrorHandling() {
do {
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(service: "Twitter")
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain()
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter")
do {
try keychain.set("kishikawa_katsumi", key: "username")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
try keychain.set("password_1234", key: "password")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let username = try keychain.get("username")
XCTAssertEqual(username, "kishikawa_katsumi")
} catch {
XCTFail("error occurred")
}
do {
let password = try keychain.get("password")
XCTAssertEqual(password, "password_1234")
} catch {
XCTFail("error occurred")
}
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter")
do {
try keychain.set("katsumi_kishikawa", key: "username")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
try keychain.set("1234_password", key: "password")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let username = try keychain.get("username")
XCTAssertEqual(username, "katsumi_kishikawa")
} catch {
XCTFail("error occurred")
}
do {
let password = try keychain.get("password")
XCTAssertEqual(password, "1234_password")
} catch {
XCTFail("error occurred")
}
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter")
do {
try keychain.remove("username")
XCTAssertNil(try! keychain.get("username"))
} catch {
XCTFail("error occurred")
}
do {
try keychain.remove("password")
XCTAssertNil(try! keychain.get("username"))
} catch {
XCTFail("error occurred")
}
}
}
// MARK:
func testSetStringWithCustomService() {
let username_1 = "kishikawakatsumi"
let password_1 = "password1234"
let username_2 = "kishikawa_katsumi"
let password_2 = "password_1234"
let username_3 = "k_katsumi"
let password_3 = "12341234"
let service_1 = ""
let service_2 = "com.kishikawakatsumi.KeychainAccess"
let service_3 = "example.com"
do { try Keychain().removeAll() } catch {}
do { try Keychain(service: service_1).removeAll() } catch {}
do { try Keychain(service: service_2).removeAll() } catch {}
do { try Keychain(service: service_3).removeAll() } catch {}
XCTAssertNil(try! Keychain().get("username"), "not stored username")
XCTAssertNil(try! Keychain().get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain().set(username_1, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
do { try Keychain(service: service_1).set(username_1, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
do { try Keychain(service: service_2).set(username_2, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
do { try Keychain(service: service_3).set(username_3, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "stored username")
do { try Keychain().set(password_1, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain(service: service_1).set(password_1, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain(service: service_2).set(password_2, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain(service: service_3).set(password_3, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "stored password")
do { try Keychain().remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "left username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
do { try Keychain(service: service_1).remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
do { try Keychain(service: service_2).remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
do { try Keychain(service: service_3).remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "removed username")
do { try Keychain().remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "left password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
do { try Keychain(service: service_1).remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
do { try Keychain(service: service_2).remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
do { try Keychain(service: service_3).remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
}
// MARK:
func testProperties() {
guard #available(OSX 10.10, *) else {
return
}
let keychain = Keychain()
XCTAssertEqual(keychain.synchronizable, false)
XCTAssertEqual(keychain.synchronizable(true).synchronizable, true)
XCTAssertEqual(keychain.synchronizable(false).synchronizable, false)
XCTAssertEqual(keychain.accessibility(.afterFirstUnlock).accessibility, Accessibility.afterFirstUnlock)
XCTAssertEqual(keychain.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence).accessibility, Accessibility.whenPasscodeSetThisDeviceOnly)
XCTAssertEqual(keychain.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence).authenticationPolicy, AuthenticationPolicy.userPresence)
XCTAssertNil(keychain.label)
XCTAssertEqual(keychain.label("Label").label, "Label")
XCTAssertNil(keychain.comment)
XCTAssertEqual(keychain.comment("Comment").comment, "Comment")
XCTAssertEqual(keychain.authenticationPrompt("Prompt").authenticationPrompt, "Prompt")
}
// MARK:
func testAllKeys() {
do {
let keychain = Keychain()
keychain["key1"] = "value1"
keychain["key2"] = "value2"
keychain["key3"] = "value3"
let allKeys = keychain.allKeys()
XCTAssertEqual(allKeys.count, 3)
XCTAssertEqual(allKeys.sorted(), ["key1", "key2", "key3"])
let allItems = keychain.allItems()
XCTAssertEqual(allItems.count, 3)
let sortedItems = allItems.sorted { (item1, item2) -> Bool in
let key1 = item1["key"] as! String
let key2 = item2["key"] as! String
return key1.compare(key2) == .orderedAscending || key1.compare(key2) == .orderedSame
}
#if !os(OSX)
let service: String
let accessGroup: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[0]["service"] as? String, service)
XCTAssertEqual(sortedItems[0]["value"] as? String, "value1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AfterFirstUnlock")
XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[1]["service"] as? String, service)
XCTAssertEqual(sortedItems[1]["value"] as? String, "value2")
XCTAssertEqual(sortedItems[1]["key"] as? String, "key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlock")
XCTAssertEqual(sortedItems[2]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[2]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[2]["service"] as? String, service)
XCTAssertEqual(sortedItems[2]["value"] as? String, "value3")
XCTAssertEqual(sortedItems[2]["key"] as? String, "key3")
XCTAssertEqual(sortedItems[2]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[2]["accessibility"] as? String, "AfterFirstUnlock")
#else
XCTAssertEqual(sortedItems[0]["service"] as? String, "com.kishikawakatsumi.KeychainAccess.TestHost")
XCTAssertEqual(sortedItems[0]["key"] as? String, "key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["service"] as? String, "com.kishikawakatsumi.KeychainAccess.TestHost")
XCTAssertEqual(sortedItems[1]["key"] as? String, "key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[2]["service"] as? String, "com.kishikawakatsumi.KeychainAccess.TestHost")
XCTAssertEqual(sortedItems[2]["key"] as? String, "key3")
XCTAssertEqual(sortedItems[2]["class"] as? String, "GenericPassword")
#endif
}
do {
let keychain = Keychain(service: "service1")
try! keychain
.synchronizable(true)
.accessibility(.whenUnlockedThisDeviceOnly)
.set("service1_value1", key: "service1_key1")
try! keychain
.synchronizable(false)
.accessibility(.afterFirstUnlockThisDeviceOnly)
.set("service1_value2", key: "service1_key2")
let allKeys = keychain.allKeys()
XCTAssertEqual(allKeys.count, 2)
XCTAssertEqual(allKeys.sorted(), ["service1_key1", "service1_key2"])
let allItems = keychain.allItems()
XCTAssertEqual(allItems.count, 2)
let sortedItems = allItems.sorted { (item1, item2) -> Bool in
let key1 = item1["key"] as! String
let key2 = item2["key"] as! String
return key1.compare(key2) == .orderedAscending || key1.compare(key2) == .orderedSame
}
#if !os(OSX)
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "true")
XCTAssertEqual(sortedItems[0]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[0]["value"] as? String, "service1_value1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "service1_key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "WhenUnlockedThisDeviceOnly")
XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[1]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[1]["value"] as? String, "service1_value2")
XCTAssertEqual(sortedItems[1]["key"] as? String, "service1_key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlockThisDeviceOnly")
#else
XCTAssertEqual(sortedItems[0]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "service1_key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[1]["key"] as? String, "service1_key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
#endif
}
do {
let keychain = Keychain(server: "https://google.com", protocolType: .https)
#if !targetEnvironment(macCatalyst)
try! keychain
.synchronizable(false)
.accessibility(.alwaysThisDeviceOnly)
.set("google.com_value1", key: "google.com_key1")
#else
try! keychain
.synchronizable(false)
.accessibility(.afterFirstUnlockThisDeviceOnly)
.set("google.com_value1", key: "google.com_key1")
#endif
#if !targetEnvironment(macCatalyst)
try! keychain
.synchronizable(true)
.accessibility(.always)
.set("google.com_value2", key: "google.com_key2")
#else
try! keychain
.synchronizable(true)
.accessibility(.afterFirstUnlock)
.set("google.com_value2", key: "google.com_key2")
#endif
let allKeys = keychain.allKeys()
XCTAssertEqual(allKeys.count, 2)
XCTAssertEqual(allKeys.sorted(), ["google.com_key1", "google.com_key2"])
let allItems = keychain.allItems()
XCTAssertEqual(allItems.count, 2)
let sortedItems = allItems.sorted { (item1, item2) -> Bool in
let key1 = item1["key"] as! String
let key2 = item2["key"] as! String
return key1.compare(key2) == .orderedAscending || key1.compare(key2) == .orderedSame
}
#if !os(OSX)
XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[0]["value"] as? String, "google.com_value1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "google.com_key1")
XCTAssertEqual(sortedItems[0]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[0]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[0]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[0]["protocol"] as? String, "HTTPS")
#if targetEnvironment(macCatalyst)
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AfterFirstUnlockThisDeviceOnly")
#else
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AlwaysThisDeviceOnly")
#endif
XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "true")
XCTAssertEqual(sortedItems[1]["value"] as? String, "google.com_value2")
XCTAssertEqual(sortedItems[1]["key"] as? String, "google.com_key2")
XCTAssertEqual(sortedItems[1]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[1]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[1]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[1]["protocol"] as? String, "HTTPS")
#if targetEnvironment(macCatalyst)
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlock")
#else
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "Always")
#endif
#else
XCTAssertEqual(sortedItems[0]["key"] as? String, "google.com_key1")
XCTAssertEqual(sortedItems[0]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[0]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[0]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[0]["protocol"] as? String, "HTTPS")
XCTAssertEqual(sortedItems[1]["key"] as? String, "google.com_key2")
XCTAssertEqual(sortedItems[1]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[1]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[1]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[1]["protocol"] as? String, "HTTPS")
#endif
}
#if !os(OSX)
do {
let allKeys = Keychain.allKeys(.genericPassword)
XCTAssertEqual(allKeys.count, 5)
let sortedKeys = allKeys.sorted { (key1, key2) -> Bool in
return key1.1.compare(key2.1) == .orderedAscending || key1.1.compare(key2.1) == .orderedSame
}
let service: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(sortedKeys[0].0, service)
XCTAssertEqual(sortedKeys[0].1, "key1")
XCTAssertEqual(sortedKeys[1].0, service)
XCTAssertEqual(sortedKeys[1].1, "key2")
XCTAssertEqual(sortedKeys[2].0, service)
XCTAssertEqual(sortedKeys[2].1, "key3")
XCTAssertEqual(sortedKeys[3].0, "service1")
XCTAssertEqual(sortedKeys[3].1, "service1_key1")
XCTAssertEqual(sortedKeys[4].0, "service1")
XCTAssertEqual(sortedKeys[4].1, "service1_key2")
}
do {
let allKeys = Keychain.allKeys(.internetPassword)
XCTAssertEqual(allKeys.count, 2)
let sortedKeys = allKeys.sorted { (key1, key2) -> Bool in
return key1.1.compare(key2.1) == .orderedAscending || key1.1.compare(key2.1) == .orderedSame
}
XCTAssertEqual(sortedKeys[0].0, "google.com")
XCTAssertEqual(sortedKeys[0].1, "google.com_key1")
XCTAssertEqual(sortedKeys[1].0, "google.com")
XCTAssertEqual(sortedKeys[1].1, "google.com_key2")
}
#endif
}
func testDescription() {
do {
let keychain = Keychain()
XCTAssertEqual(keychain.description, "[]")
XCTAssertEqual(keychain.debugDescription, "[]")
}
}
// MARK:
func testAuthenticationPolicy() {
guard #available(iOS 9.0, OSX 10.11, *) else {
return
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
#if os(iOS)
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence, .applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence, .applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet, .applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet, .applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .or, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .and, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
#endif
#if os(OSX)
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
#endif
}
func testIgnoringAttributeSynchronizable() {
let keychain = Keychain(service: "Twitter").synchronizable(false)
let keychainSynchronizable = Keychain(service: "Twitter").synchronizable(true)
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username", ignoringAttributeSynchronizable: false) } catch {}
do { try keychainSynchronizable.set("kishikawakatsumi_synchronizable", key: "username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertEqual(try! keychain.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
do { try keychain.set("password1234", key: "password", ignoringAttributeSynchronizable: false) } catch {}
do { try keychainSynchronizable.set("password1234_synchronizable", key: "password", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertEqual(try! keychain.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychain.get("password", ignoringAttributeSynchronizable: false), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "password1234_synchronizable", "stored password")
do { try keychain.remove("username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
do { try keychainSynchronizable.remove("username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertEqual(try! keychain.get("password", ignoringAttributeSynchronizable: false), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "password1234_synchronizable", "stored password")
do { try keychain.removeAll() } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
}
func testIgnoringAttributeSynchronizableBackwardCompatibility() {
let keychain = Keychain(service: "Twitter").synchronizable(false)
let keychainSynchronizable = Keychain(service: "Twitter").synchronizable(true)
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi", "stored username")
do { try keychainSynchronizable.set("kishikawakatsumi_synchronizable", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234", "stored password")
do { try keychainSynchronizable.set("password1234_synchronizable", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234_synchronizable", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234_synchronizable", "stored password")
do { try keychain.remove("username") } catch {}
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234_synchronizable", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234_synchronizable", "stored password")
do { try keychain.removeAll() } catch {}
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
}
}
================================================
FILE: External/KeychainAccess/Lib/KeychainAccessTests/SharedCredentialTests.swift
================================================
//
// SharedCredentialTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class SharedCredentialTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testGetSharedPassword() {
do {
let expectation = self.expectation(description: "getSharedPassword")
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https)
keychain.getSharedPassword("kishikawakatsumi") { (password, error) -> () in
XCTAssertNil(password)
XCTAssertNotNil(error)
expectation.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
}
do {
let expectation = self.expectation(description: "getSharedPassword")
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https)
keychain.getSharedPassword { (account, password, error) -> () in
XCTAssertNil(account)
XCTAssertNil(password)
XCTAssertNotNil(error)
expectation.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
}
}
func testGeneratePassword() {
do {
var passwords = Set()
for _ in 0...100_000 {
let password = Keychain.generatePassword()
#if swift(>=4.2)
XCTAssertEqual(password.count, "xxx-xxx-xxx-xxx".count)
#else
XCTAssertEqual(password.characters.count, "xxx-xxx-xxx-xxx".characters.count)
#endif
XCTAssertFalse(passwords.contains(password))
passwords.insert(password)
}
}
}
}
================================================
FILE: External/KeychainAccess/Lib/Rakefile
================================================
require 'xcjobs'
require 'json'
def xcode_version
`xcodebuild -version`.split("\n").first.scan(/\d+/).join('.')
end
def destinations(platform: 'iphonesimulator')
if platform == 'iphonesimulator'
if xcode_version.start_with?('11')
[ 'name=iPhone 11 Pro,OS=13.0'
]
elsif xcode_version.start_with?('10')
[ 'name=iPhone 5s,OS=12.0',
'name=iPhone 6,OS=12.0',
'name=iPhone 6s Plus,OS=12.0',
'name=iPhone SE,OS=12.0',
'name=iPad Air 2,OS=12.0',
'name=iPad Pro (9.7-inch),OS=12.0',
'name=iPad Pro (12.9-inch),OS=12.0'
]
elsif xcode_version.start_with?('9.4')
[ 'name=iPhone 5s,OS=11.4',
'name=iPhone 6,OS=11.4',
'name=iPhone 6s Plus,OS=11.4',
'name=iPhone SE,OS=11.4',
'name=iPad Air 2,OS=11.4',
'name=iPad Pro (9.7-inch),OS=11.4',
'name=iPad Pro (12.9-inch),OS=11.4'
]
elsif xcode_version.start_with?('9.3')
[ 'name=iPhone 5s,OS=11.0.1',
'name=iPhone 5s,OS=11.1',
'name=iPhone 6,OS=11.2',
'name=iPhone 6s Plus,OS=11.3',
'name=iPhone SE,OS=11.0.1',
'name=iPad Air 2,OS=11.1',
'name=iPad Pro (9.7-inch),OS=11.2',
'name=iPad Pro (12.9-inch),OS=11.3'
]
elsif xcode_version.start_with?('9.2')
[ 'name=iPhone 5s,OS=11.2',
'name=iPhone 5s,OS=11.2',
'name=iPhone 6,OS=11.2',
'name=iPhone 6s Plus,OS=11.2',
'name=iPhone SE,OS=11.2',
'name=iPad Air 2,OS=11.2',
'name=iPad Pro (9.7-inch),OS=11.2',
'name=iPad Pro (12.9-inch),OS=11.2'
]
elsif xcode_version.start_with?('9.1')
[ 'name=iPhone 5s,OS=11.1',
'name=iPhone 5s,OS=11.1',
'name=iPhone 6,OS=11.1',
'name=iPhone 6s Plus,OS=11.1',
'name=iPhone SE,OS=11.1',
'name=iPad Air 2,OS=11.1',
'name=iPad Pro (9.7-inch),OS=11.1',
'name=iPad Pro (12.9-inch),OS=11.1'
]
elsif xcode_version.start_with?('9')
[ 'name=iPhone 5,OS=10.0',
'name=iPhone 5s,OS=10.0',
'name=iPhone 6,OS=10.0',
'name=iPhone 6s Plus,OS=10.3.1',
'name=iPhone SE,OS=10.3.1',
'name=iPhone 7,OS=11.0',
'name=iPad Air 2,OS=10.0',
'name=iPad Pro (9.7-inch),OS=10.0',
'name=iPad Pro (12.9-inch),OS=10.0',
'name=iPad Pro (10.5-inch),OS=11.0'
]
else
[ 'name=iPhone 5,OS=10.0',
'name=iPhone 5s,OS=10.0',
'name=iPhone 6,OS=10.0',
'name=iPhone 6s Plus,OS=10.3.1',
'name=iPhone SE,OS=10.3.1',
'name=iPad Air 2,OS=10.0',
'name=iPad Pro (9.7-inch),OS=10.0',
'name=iPad Pro (12.9-inch),OS=10.0'
]
end
elsif platform == 'watchsimulator'
if xcode_version.start_with?('11')
[ 'name=Apple Watch Series 4 - 44mm,OS=6.0'
]
elsif xcode_version.start_with?('10')
[ 'name=Apple Watch Series 4 - 40mm,OS=5.0',
'name=Apple Watch Series 4 - 44mm,OS=5.0'
]
elsif xcode_version.start_with?('9.4')
[ 'name=Apple Watch Series 3 - 38mm,OS=4.3',
'name=Apple Watch Series 3 - 42mm,OS=4.3'
]
elsif xcode_version.start_with?('9.3')
[ 'name=Apple Watch - 38mm,OS=4.3',
'name=Apple Watch - 42mm,OS=4.3',
'name=Apple Watch Series 2 - 42mm,OS=4.3'
]
elsif xcode_version.start_with?('9.2')
[ 'name=Apple Watch - 38mm,OS=4.2',
'name=Apple Watch - 42mm,OS=4.2',
'name=Apple Watch Series 2 - 42mm,OS=4.2'
]
elsif xcode_version.start_with?('9.1')
[ 'name=Apple Watch - 38mm,OS=4.1',
'name=Apple Watch - 42mm,OS=4.1',
'name=Apple Watch Series 2 - 42mm,OS=4.1'
]
elsif xcode_version.start_with?('9')
[ 'name=Apple Watch - 38mm,OS=3.2',
'name=Apple Watch - 42mm,OS=4.0',
'name=Apple Watch Series 2 - 42mm,OS=4.0'
]
else
[ 'name=Apple Watch - 38mm,OS=3.2',
'name=Apple Watch Series 2 - 42mm,OS=3.2'
]
end
elsif platform == 'appletvsimulator'
if xcode_version.start_with?('11')
[ 'name=Apple TV 4K,OS=13.0'
]
elsif xcode_version.start_with?('10')
[ 'name=Apple TV 4K,OS=12.0'
]
elsif xcode_version.start_with?('9.4')
[ 'name=Apple TV 4K,OS=11.4'
]
elsif xcode_version.start_with?('9.3')
[ 'name=Apple TV 4K,OS=11.3'
]
elsif xcode_version.start_with?('9.2')
[ 'name=Apple TV 4K,OS=11.2'
]
elsif xcode_version.start_with?('9.1')
[ 'name=Apple TV 4K,OS=11.1'
]
elsif xcode_version.start_with?('9')
[ 'name=Apple TV 1080p,OS=10.2',
'name=Apple TV 1080p,OS=11.0'
]
else
[ 'name=Apple TV 1080p,OS=10.2'
]
end
else
[
'platform=OS X,arch=x86_64'
]
end
end
def supportedPlatforms
['macosx', 'iphoneos', 'iphonesimulator', 'watchos', 'watchsimulator', 'appletvos', 'appletvsimulator']
end
def configurations
['Debug', 'Release']
end
desc "build for all platforms"
task :build do |t|
supportedPlatforms
.product(configurations)
.map { |platform, configuration| Rake::Task["build:#{platform}:#{configuration.downcase}"] }
.map(&:invoke)
end
namespace :build do
supportedPlatforms.product(configurations).each do |platform, configuration|
XCJobs::Build.new("#{platform}:#{configuration.downcase}") do |t|
t.project = 'KeychainAccess'
t.scheme = 'KeychainAccess'
t.sdk = platform
t.configuration = configuration
t.build_dir = 'build'
t.hide_shell_script_environment = true
t.formatter = 'xcpretty -c'
if ENV['CI']
t.add_build_setting('CODE_SIGN_IDENTITY', '')
t.add_build_setting('CODE_SIGNING_REQUIRED', 'NO')
end
if xcode_version.start_with?('11')
t.add_build_setting('SWIFT_VERSION', '5.1')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 11,OS=13.0')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch Series 4 - 44mm,OS=6.0')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=13.0')
end
elsif xcode_version.start_with?('10.3')
t.add_build_setting('SWIFT_VERSION', '5.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=12.0')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch Series 4 - 44mm,OS=5.0')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=12.0')
end
elsif xcode_version.start_with?('10')
t.add_build_setting('SWIFT_VERSION', '4.2')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=12.0')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch Series 4 - 44mm,OS=5.0')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=12.0')
end
elsif xcode_version.start_with?('9.4')
t.add_build_setting('SWIFT_VERSION', '4.1')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.4')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch Series 3 - 42mm,OS=4.3')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.4')
end
elsif xcode_version.start_with?('9.3')
t.add_build_setting('SWIFT_VERSION', '4.1')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.3')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.3')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.3')
end
elsif xcode_version.start_with?('9.2')
t.add_build_setting('SWIFT_VERSION', '4.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.2')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.2')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.2')
end
elsif xcode_version.start_with?('9.1')
t.add_build_setting('SWIFT_VERSION', '4.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.1')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.1')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.1')
end
elsif xcode_version.start_with?('9')
t.add_build_setting('SWIFT_VERSION', '4.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.0')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.0')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 1080p,OS=11.0')
end
else
t.add_build_setting('SWIFT_VERSION', '3.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=10.3.1')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=3.2')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 1080p,OS=10.0')
end
end
end
end
task :carthage do
sh %[echo 'github \"kishikawakatsumi/KeychainAccess\"' > Cartfile]
if xcode_version.start_with?('11')
sh %[echo SWIFT_VERSION=\"5.1\" > swift.xcconfig]
elsif xcode_version.start_with?('10.3')
sh %[echo SWIFT_VERSION=\"5.0\" > swift.xcconfig]
elsif xcode_version.start_with?('10')
sh %[echo SWIFT_VERSION=\"4.2\" > swift.xcconfig]
elsif xcode_version.start_with?('9.4')
sh %[echo SWIFT_VERSION=\"4.1\" > swift.xcconfig]
elsif xcode_version.start_with?('9.3')
sh %[echo SWIFT_VERSION=\"4.1\" > swift.xcconfig]
elsif xcode_version.start_with?('9')
sh %[echo SWIFT_VERSION=\"4.0\" > swift.xcconfig]
else
sh %[echo SWIFT_VERSION=\"3.0\" > swift.xcconfig]
end
sh %[XCODE_XCCONFIG_FILE=`pwd`/swift.xcconfig carthage update --no-use-binaries]
sh %[find . -name '*.bcsymbolmap' | xargs grep swiftlang]
end
end
namespace :test do
supportedPlatforms
.select { |platform| platform == 'macosx' || platform == 'iphonesimulator' || platform == 'appletvsimulator' }
.each do |platform|
task platform do |t|
configurations.each do |configuration|
destinations(platform: platform)
.map { |destination| Rake::Task["test:#{platform}:#{configuration.downcase}:#{destination}"] }
.map(&:invoke)
end
end
end
end
namespace :test do
supportedPlatforms
.select { |platform| platform == 'macosx' || platform == 'iphonesimulator' || platform == 'appletvsimulator' }
.product(configurations)
.each do |platform, configuration|
destinations(platform: platform).each do |destination|
XCJobs::Test.new("#{platform}:#{configuration.downcase}:#{destination}") do |t|
t.project = 'KeychainAccess'
t.scheme = 'KeychainAccess'
t.sdk = platform
t.configuration = configuration
t.add_destination(destination)
t.coverage = true
t.build_dir = 'build'
t.hide_shell_script_environment = true
if xcode_version.start_with?('11')
t.add_build_setting('SWIFT_VERSION', '5.1')
elsif xcode_version.start_with?('10.3')
t.add_build_setting('SWIFT_VERSION', '5.0')
elsif xcode_version.start_with?('10')
t.add_build_setting('SWIFT_VERSION', '4.2')
elsif xcode_version.start_with?('9.4')
t.add_build_setting('SWIFT_VERSION', '4.1')
elsif xcode_version.start_with?('9.3')
t.add_build_setting('SWIFT_VERSION', '4.1')
elsif xcode_version.start_with?('9')
t.add_build_setting('SWIFT_VERSION', '4.0')
else
t.add_build_setting('SWIFT_VERSION', '3.0')
end
t.after_action do
build_coverage_reports()
puts `curl -L https://codecov.io/bash | bash -s -- -f 'coverage.txt'`
end
end
end
end
end
def build_coverage_reports()
project_name = 'KeychainAccess'
profdata = Dir.glob(File.join('build', '/**/Coverage.profdata')).first
Dir.glob(File.join('build', "/**/#{project_name}")) do |target|
output = `xcrun llvm-cov report -instr-profile "#{profdata}" "#{target}" -arch=x86_64`
if $?.success?
puts output
`xcrun llvm-cov show -instr-profile "#{profdata}" "#{target}" -arch=x86_64 -use-color=0 > coverage.txt`
break
end
end
end
================================================
FILE: External/KeychainAccess/Lib/Scripts/add_key.sh
================================================
#!/bin/sh
security create-keychain -p travis build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p travis build.keychain
security set-keychain-settings -t 3600 -l ~/Library/Keychains/build.keychain
security import ./Lib/Certificates/apple.cer -k ~/Library/Keychains/build.keychain -T /usr/bin/codesign
security import ./Lib/Certificates/ios_developer.p12 -k ~/Library/Keychains/build.keychain -P $PASSPHRASE -T /usr/bin/codesign
security import ./Lib/Certificates/developer_id_app.p12 -k ~/Library/Keychains/build.keychain -P $PASSPHRASE -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k travis build.keychain
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp ./Lib/Certificates/*.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
cp ./Lib/Certificates/*.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/
================================================
FILE: External/KeychainAccess/Lib/Scripts/decode_cert.sh
================================================
#!/bin/sh
CERT_DIR="./Lib/Certificates"
FILES=('ios_developer.p12' 'developer_id_app.p12' 'iOS_Development.mobileprovision'\
'tvOS_Development.mobileprovision' 'KeychainAccess_Tests.provisionprofile')
for file in ${FILES[@]}; do
openssl aes-256-cbc -k "$ENCRYPTION_SECRET" -in "$CERT_DIR"/"$file".enc -d -a -out "$CERT_DIR"/"$file"
done
================================================
FILE: External/KeychainAccess/Lib/TestHost/AppDelegate.swift
================================================
//
// AppDelegate.swift
// TestHost
//
// Created by kishikawa katsumi on 7/10/16.
// Copyright © 2016 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(OSX)
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(aNotification: NSNotification) {}
}
#else
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
#if swift(>=4.2)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#else
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#endif
}
#endif
================================================
FILE: External/KeychainAccess/Lib/TestHost/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
LSRequiresIPhoneOS
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UIRequiresFullScreen
NSPrincipalClass
$(PRINCIPAL_CLASS)
================================================
FILE: External/KeychainAccess/Lib/TestHost/TestHost.entitlements
================================================
keychain-access-groups
$(AppIdentifierPrefix)com.kishikawakatsumi.KeychainAccess.TestHost
$(AppIdentifierPrefix)shared
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/EnumTests.swift
================================================
//
// EnumTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class EnumTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testItemClass() {
do {
let itemClass = ItemClass(rawValue: kSecClassGenericPassword as String)
XCTAssertEqual(itemClass, .genericPassword)
XCTAssertEqual(itemClass?.description, "GenericPassword")
}
do {
let itemClass = ItemClass(rawValue: kSecClassInternetPassword as String)
XCTAssertEqual(itemClass, .internetPassword)
XCTAssertEqual(itemClass?.description, "InternetPassword")
}
do {
let itemClass = ItemClass(rawValue: kSecClassCertificate as String)
XCTAssertNil(itemClass)
}
do {
let itemClass = ItemClass(rawValue: kSecClassKey as String)
XCTAssertNil(itemClass)
}
do {
let itemClass = ItemClass(rawValue: kSecClassIdentity as String)
XCTAssertNil(itemClass)
}
}
func testProtocolType() {
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTP as String)
XCTAssertEqual(protocolType, .ftp)
XCTAssertEqual(protocolType?.description, "FTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPAccount as String)
XCTAssertEqual(protocolType, .ftpAccount)
XCTAssertEqual(protocolType?.description, "FTPAccount")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTP as String)
XCTAssertEqual(protocolType, .http)
XCTAssertEqual(protocolType?.description, "HTTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRC as String)
XCTAssertEqual(protocolType, .irc)
XCTAssertEqual(protocolType?.description, "IRC")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTP as String)
XCTAssertEqual(protocolType, .nntp)
XCTAssertEqual(protocolType?.description, "NNTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3 as String)
XCTAssertEqual(protocolType, .pop3)
XCTAssertEqual(protocolType?.description, "POP3")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMTP as String)
XCTAssertEqual(protocolType, .smtp)
XCTAssertEqual(protocolType?.description, "SMTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSOCKS as String)
XCTAssertEqual(protocolType, .socks)
XCTAssertEqual(protocolType?.description, "SOCKS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAP as String)
XCTAssertEqual(protocolType, .imap)
XCTAssertEqual(protocolType?.description, "IMAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAP as String)
XCTAssertEqual(protocolType, .ldap)
XCTAssertEqual(protocolType?.description, "LDAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolAppleTalk as String)
XCTAssertEqual(protocolType, .appleTalk)
XCTAssertEqual(protocolType?.description, "AppleTalk")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolAFP as String)
XCTAssertEqual(protocolType, .afp)
XCTAssertEqual(protocolType?.description, "AFP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnet as String)
XCTAssertEqual(protocolType, .telnet)
XCTAssertEqual(protocolType?.description, "Telnet")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSSH as String)
XCTAssertEqual(protocolType, .ssh)
XCTAssertEqual(protocolType?.description, "SSH")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPS as String)
XCTAssertEqual(protocolType, .ftps)
XCTAssertEqual(protocolType?.description, "FTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPS as String)
XCTAssertEqual(protocolType, .https)
XCTAssertEqual(protocolType?.description, "HTTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPProxy as String)
XCTAssertEqual(protocolType, .httpProxy)
XCTAssertEqual(protocolType?.description, "HTTPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPSProxy as String)
XCTAssertEqual(protocolType, .httpsProxy)
XCTAssertEqual(protocolType?.description, "HTTPSProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPProxy as String)
XCTAssertEqual(protocolType, .ftpProxy)
XCTAssertEqual(protocolType?.description, "FTPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMB as String)
XCTAssertEqual(protocolType, .smb)
XCTAssertEqual(protocolType?.description, "SMB")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSP as String)
XCTAssertEqual(protocolType, .rtsp)
XCTAssertEqual(protocolType?.description, "RTSP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSPProxy as String)
XCTAssertEqual(protocolType, .rtspProxy)
XCTAssertEqual(protocolType?.description, "RTSPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolDAAP as String)
XCTAssertEqual(protocolType, .daap)
XCTAssertEqual(protocolType?.description, "DAAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolEPPC as String)
XCTAssertEqual(protocolType, .eppc)
XCTAssertEqual(protocolType?.description, "EPPC")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIPP as String)
XCTAssertEqual(protocolType, .ipp)
XCTAssertEqual(protocolType?.description, "IPP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTPS as String)
XCTAssertEqual(protocolType, .nntps)
XCTAssertEqual(protocolType?.description, "NNTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAPS as String)
XCTAssertEqual(protocolType, .ldaps)
XCTAssertEqual(protocolType?.description, "LDAPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnetS as String)
XCTAssertEqual(protocolType, .telnetS)
XCTAssertEqual(protocolType?.description, "TelnetS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAPS as String)
XCTAssertEqual(protocolType, .imaps)
XCTAssertEqual(protocolType?.description, "IMAPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRCS as String)
XCTAssertEqual(protocolType, .ircs)
XCTAssertEqual(protocolType?.description, "IRCS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3S as String)
XCTAssertEqual(protocolType, .pop3S)
XCTAssertEqual(protocolType?.description, "POP3S")
}
}
func testAuthenticationType() {
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeNTLM as String)
XCTAssertEqual(authenticationType, .ntlm)
XCTAssertEqual(authenticationType?.description, "NTLM")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeMSN as String)
XCTAssertEqual(authenticationType, .msn)
XCTAssertEqual(authenticationType?.description, "MSN")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDPA as String)
XCTAssertEqual(authenticationType, .dpa)
XCTAssertEqual(authenticationType?.description, "DPA")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeRPA as String)
XCTAssertEqual(authenticationType, .rpa)
XCTAssertEqual(authenticationType?.description, "RPA")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPBasic as String)
XCTAssertEqual(authenticationType, .httpBasic)
XCTAssertEqual(authenticationType?.description, "HTTPBasic")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPDigest as String)
XCTAssertEqual(authenticationType, .httpDigest)
XCTAssertEqual(authenticationType?.description, "HTTPDigest")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTMLForm as String)
XCTAssertEqual(authenticationType, .htmlForm)
XCTAssertEqual(authenticationType?.description, "HTMLForm")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDefault as String)
XCTAssertEqual(authenticationType, .default)
XCTAssertEqual(authenticationType?.description, "Default")
}
}
func testAccessibility() {
guard #available(OSX 10.10, *) else {
return
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlocked as String)
XCTAssertEqual(accessibility, .whenUnlocked)
XCTAssertEqual(accessibility?.description, "WhenUnlocked")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlock as String)
XCTAssertEqual(accessibility, .afterFirstUnlock)
XCTAssertEqual(accessibility?.description, "AfterFirstUnlock")
}
#if !targetEnvironment(macCatalyst)
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlways as String)
XCTAssertEqual(accessibility, .always)
XCTAssertEqual(accessibility?.description, "Always")
}
#endif
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly as String)
XCTAssertEqual(accessibility, .whenPasscodeSetThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "WhenPasscodeSetThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlockedThisDeviceOnly as String)
XCTAssertEqual(accessibility, .whenUnlockedThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "WhenUnlockedThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)
XCTAssertEqual(accessibility, .afterFirstUnlockThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "AfterFirstUnlockThisDeviceOnly")
}
#if !targetEnvironment(macCatalyst)
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlwaysThisDeviceOnly as String)
XCTAssertEqual(accessibility, .alwaysThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "AlwaysThisDeviceOnly")
}
#endif
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/ErrorTypeTests.swift
================================================
//
// ErrorTypeTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class ErrorTypeTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testErrorType() {
do {
let status = Status(rawValue: errSecSuccess)
XCTAssertEqual(status, .success)
XCTAssertEqual(status?.description, "No error.")
}
do {
let status = Status(rawValue: errSecUnimplemented)
XCTAssertEqual(status, .unimplemented)
XCTAssertEqual(status?.description, "Function or operation not implemented.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecDiskFull)
XCTAssertEqual(status, .diskFull)
XCTAssertEqual(status?.description, "The disk is full.")
}
#endif
do {
let status = Status(rawValue: errSecIO)
XCTAssertEqual(status, .io)
XCTAssertEqual(status?.description, "I/O error (bummers)")
}
#if os(iOS)
do {
let status = Status(rawValue: errSecOpWr)
XCTAssertEqual(status, .opWr)
XCTAssertEqual(status?.description, "file already open with with write permission")
}
#endif
do {
let status = Status(rawValue: errSecParam)
XCTAssertEqual(status, .param)
XCTAssertEqual(status?.description, "One or more parameters passed to a function were not valid.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecWrPerm)
XCTAssertEqual(status, .wrPerm)
XCTAssertEqual(status?.description, "write permissions error")
}
#endif
do {
let status = Status(rawValue: errSecAllocate)
XCTAssertEqual(status, .allocate)
XCTAssertEqual(status?.description, "Failed to allocate memory.")
}
do {
let status = Status(rawValue: errSecUserCanceled)
XCTAssertEqual(status, .userCanceled)
XCTAssertEqual(status?.description, "User canceled the operation.")
}
do {
let status = Status(rawValue: errSecBadReq)
XCTAssertEqual(status, .badReq)
XCTAssertEqual(status?.description, "Bad parameter or invalid state for operation.")
}
do {
let status = Status(rawValue: errSecInternalComponent)
XCTAssertEqual(status, .internalComponent)
XCTAssertEqual(status?.description, "")
}
do {
let status = Status(rawValue: errSecNotAvailable)
XCTAssertEqual(status, .notAvailable)
XCTAssertEqual(status?.description, "No keychain is available. You may need to restart your computer.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecReadOnly)
XCTAssertEqual(status, .readOnly)
XCTAssertEqual(status?.description, "This keychain cannot be modified.")
}
#endif
do {
let status = Status(rawValue: errSecAuthFailed)
XCTAssertEqual(status, .authFailed)
XCTAssertEqual(status?.description, "The user name or passphrase you entered is not correct.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecNoSuchKeychain)
XCTAssertEqual(status, .noSuchKeychain)
XCTAssertEqual(status?.description, "The specified keychain could not be found.")
}
do {
let status = Status(rawValue: errSecInvalidKeychain)
XCTAssertEqual(status, .invalidKeychain)
XCTAssertEqual(status?.description, "The specified keychain is not a valid keychain file.")
}
do {
let status = Status(rawValue: errSecDuplicateKeychain)
XCTAssertEqual(status, .duplicateKeychain)
XCTAssertEqual(status?.description, "A keychain with the same name already exists.")
}
do {
let status = Status(rawValue: errSecDuplicateCallback)
XCTAssertEqual(status, .duplicateCallback)
XCTAssertEqual(status?.description, "The specified callback function is already installed.")
}
do {
let status = Status(rawValue: errSecInvalidCallback)
XCTAssertEqual(status, .invalidCallback)
XCTAssertEqual(status?.description, "The specified callback function is not valid.")
}
#endif
do {
let status = Status(rawValue: errSecDuplicateItem)
XCTAssertEqual(status, .duplicateItem)
XCTAssertEqual(status?.description, "The specified item already exists in the keychain.")
}
do {
let status = Status(rawValue: errSecItemNotFound)
XCTAssertEqual(status, .itemNotFound)
XCTAssertEqual(status?.description, "The specified item could not be found in the keychain.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecBufferTooSmall)
XCTAssertEqual(status, .bufferTooSmall)
XCTAssertEqual(status?.description, "There is not enough memory available to use the specified item.")
}
do {
let status = Status(rawValue: errSecDataTooLarge)
XCTAssertEqual(status, .dataTooLarge)
XCTAssertEqual(status?.description, "This item contains information which is too large or in a format that cannot be displayed.")
}
do {
let status = Status(rawValue: errSecNoSuchAttr)
XCTAssertEqual(status, .noSuchAttr)
XCTAssertEqual(status?.description, "The specified attribute does not exist.")
}
do {
let status = Status(rawValue: errSecInvalidItemRef)
XCTAssertEqual(status, .invalidItemRef)
XCTAssertEqual(status?.description, "The specified item is no longer valid. It may have been deleted from the keychain.")
}
do {
let status = Status(rawValue: errSecInvalidSearchRef)
XCTAssertEqual(status, .invalidSearchRef)
XCTAssertEqual(status?.description, "Unable to search the current keychain.")
}
do {
let status = Status(rawValue: errSecNoSuchClass)
XCTAssertEqual(status, .noSuchClass)
XCTAssertEqual(status?.description, "The specified item does not appear to be a valid keychain item.")
}
do {
let status = Status(rawValue: errSecNoDefaultKeychain)
XCTAssertEqual(status, .noDefaultKeychain)
XCTAssertEqual(status?.description, "A default keychain could not be found.")
}
#endif
do {
let status = Status(rawValue: errSecInteractionNotAllowed)
XCTAssertEqual(status, .interactionNotAllowed)
XCTAssertEqual(status?.description, "User interaction is not allowed.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecReadOnlyAttr)
XCTAssertEqual(status, .readOnlyAttr)
XCTAssertEqual(status?.description, "The specified attribute could not be modified.")
}
do {
let status = Status(rawValue: errSecWrongSecVersion)
XCTAssertEqual(status, .wrongSecVersion)
XCTAssertEqual(status?.description, "This keychain was created by a different version of the system software and cannot be opened.")
}
do {
let status = Status(rawValue: errSecKeySizeNotAllowed)
XCTAssertEqual(status, .keySizeNotAllowed)
XCTAssertEqual(status?.description, "This item specifies a key size which is too large.")
}
do {
let status = Status(rawValue: errSecNoStorageModule)
XCTAssertEqual(status, .noStorageModule)
XCTAssertEqual(status?.description, "A required component (data storage module) could not be loaded. You may need to restart your computer.")
}
do {
let status = Status(rawValue: errSecNoCertificateModule)
XCTAssertEqual(status, .noCertificateModule)
XCTAssertEqual(status?.description, "A required component (certificate module) could not be loaded. You may need to restart your computer.")
}
do {
let status = Status(rawValue: errSecNoPolicyModule)
XCTAssertEqual(status, .noPolicyModule)
XCTAssertEqual(status?.description, "A required component (policy module) could not be loaded. You may need to restart your computer.")
}
do {
let status = Status(rawValue: errSecInteractionRequired)
XCTAssertEqual(status, .interactionRequired)
XCTAssertEqual(status?.description, "User interaction is required, but is currently not allowed.")
}
do {
let status = Status(rawValue: errSecDataNotAvailable)
XCTAssertEqual(status, .dataNotAvailable)
XCTAssertEqual(status?.description, "The contents of this item cannot be retrieved.")
}
do {
let status = Status(rawValue: errSecDataNotModifiable)
XCTAssertEqual(status, .dataNotModifiable)
XCTAssertEqual(status?.description, "The contents of this item cannot be modified.")
}
do {
let status = Status(rawValue: errSecCreateChainFailed)
XCTAssertEqual(status, .createChainFailed)
XCTAssertEqual(status?.description, "One or more certificates required to validate this certificate cannot be found.")
}
do {
let status = Status(rawValue: errSecInvalidPrefsDomain)
XCTAssertEqual(status, .invalidPrefsDomain)
XCTAssertEqual(status?.description, "The specified preferences domain is not valid.")
}
do {
let status = Status(rawValue: errSecInDarkWake)
XCTAssertEqual(status, .inDarkWake)
XCTAssertEqual(status?.description, "In dark wake, no UI possible")
}
do {
let status = Status(rawValue: errSecACLNotSimple)
XCTAssertEqual(status, .aclNotSimple)
XCTAssertEqual(status?.description, "The specified access control list is not in standard (simple) form.")
}
do {
let status = Status(rawValue: errSecPolicyNotFound)
XCTAssertEqual(status, .policyNotFound)
XCTAssertEqual(status?.description, "The specified policy cannot be found.")
}
do {
let status = Status(rawValue: errSecInvalidTrustSetting)
XCTAssertEqual(status, .invalidTrustSetting)
XCTAssertEqual(status?.description, "The specified trust setting is invalid.")
}
do {
let status = Status(rawValue: errSecNoAccessForItem)
XCTAssertEqual(status, .noAccessForItem)
XCTAssertEqual(status?.description, "The specified item has no access control.")
}
do {
let status = Status(rawValue: errSecInvalidOwnerEdit)
XCTAssertEqual(status, .invalidOwnerEdit)
XCTAssertEqual(status?.description, "Invalid attempt to change the owner of this item.")
}
do {
let status = Status(rawValue: errSecTrustNotAvailable)
XCTAssertEqual(status, .trustNotAvailable)
XCTAssertEqual(status?.description, "No trust results are available.")
}
do {
let status = Status(rawValue: errSecUnsupportedFormat)
XCTAssertEqual(status, .unsupportedFormat)
XCTAssertEqual(status?.description, "Import/Export format unsupported.")
}
do {
let status = Status(rawValue: errSecUnknownFormat)
XCTAssertEqual(status, .unknownFormat)
XCTAssertEqual(status?.description, "Unknown format in import.")
}
do {
let status = Status(rawValue: errSecKeyIsSensitive)
XCTAssertEqual(status, .keyIsSensitive)
XCTAssertEqual(status?.description, "Key material must be wrapped for export.")
}
do {
let status = Status(rawValue: errSecMultiplePrivKeys)
XCTAssertEqual(status, .multiplePrivKeys)
XCTAssertEqual(status?.description, "An attempt was made to import multiple private keys.")
}
do {
let status = Status(rawValue: errSecPassphraseRequired)
XCTAssertEqual(status, .passphraseRequired)
XCTAssertEqual(status?.description, "Passphrase is required for import/export.")
}
do {
let status = Status(rawValue: errSecInvalidPasswordRef)
XCTAssertEqual(status, .invalidPasswordRef)
XCTAssertEqual(status?.description, "The password reference was invalid.")
}
do {
let status = Status(rawValue: errSecInvalidTrustSettings)
XCTAssertEqual(status, .invalidTrustSettings)
XCTAssertEqual(status?.description, "The Trust Settings Record was corrupted.")
}
do {
let status = Status(rawValue: errSecNoTrustSettings)
XCTAssertEqual(status, .noTrustSettings)
XCTAssertEqual(status?.description, "No Trust Settings were found.")
}
do {
let status = Status(rawValue: errSecPkcs12VerifyFailure)
XCTAssertEqual(status, .pkcs12VerifyFailure)
XCTAssertEqual(status?.description, "MAC verification failed during PKCS12 import (wrong password?)")
}
do {
let errSecInvalidCertificate: OSStatus = -26265
let status = Status(rawValue: errSecInvalidCertificate)
XCTAssertEqual(status, .invalidCertificate)
XCTAssertEqual(status?.description, "This certificate could not be decoded.")
}
do {
let status = Status(rawValue: errSecNotSigner)
XCTAssertEqual(status, .notSigner)
XCTAssertEqual(status?.description, "A certificate was not signed by its proposed parent.")
}
do {
let errSecPolicyDenied: OSStatus = -26270
let status = Status(rawValue: errSecPolicyDenied)
XCTAssertEqual(status, .policyDenied)
XCTAssertEqual(status?.description, "The certificate chain was not trusted due to a policy not accepting it.")
}
do {
let errSecInvalidKey: OSStatus = -26274
let status = Status(rawValue: errSecInvalidKey)
XCTAssertEqual(status, .invalidKey)
XCTAssertEqual(status?.description, "The provided key material was not valid.")
}
#endif
do {
let status = Status(rawValue: errSecDecode)
XCTAssertEqual(status, .decode)
XCTAssertEqual(status?.description, "Unable to decode the provided data.")
}
do {
let errSecInternal: OSStatus = -26276
let status = Status(rawValue: errSecInternal)
XCTAssertEqual(status, .internal)
XCTAssertEqual(status?.description, "An internal error occurred in the Security framework.")
}
#if os(OSX)
do {
let status = Status(rawValue: errSecServiceNotAvailable)
XCTAssertEqual(status, .serviceNotAvailable)
XCTAssertEqual(status?.description, "The required service is not available.")
}
do {
let errSecUnsupportedAlgorithm: OSStatus = -26268
let status = Status(rawValue: errSecUnsupportedAlgorithm)
XCTAssertEqual(status, .unsupportedAlgorithm)
XCTAssertEqual(status?.description, "An unsupported algorithm was encountered.")
}
do {
let errSecUnsupportedOperation: OSStatus = -26271
let status = Status(rawValue: errSecUnsupportedOperation)
XCTAssertEqual(status, .unsupportedOperation)
XCTAssertEqual(status?.description, "The operation you requested is not supported by this key.")
}
do {
let errSecUnsupportedPadding: OSStatus = -26273
let status = Status(rawValue: errSecUnsupportedPadding)
XCTAssertEqual(status, .unsupportedPadding)
XCTAssertEqual(status?.description, "The padding you requested is not supported.")
}
do {
let errSecItemInvalidKey: OSStatus = -34000
let status = Status(rawValue: errSecItemInvalidKey)
XCTAssertEqual(status, .itemInvalidKey)
XCTAssertEqual(status?.description, "A string key in dictionary is not one of the supported keys.")
}
do {
let errSecItemInvalidKeyType: OSStatus = -34001
let status = Status(rawValue: errSecItemInvalidKeyType)
XCTAssertEqual(status, .itemInvalidKeyType)
XCTAssertEqual(status?.description, "A key in a dictionary is neither a CFStringRef nor a CFNumberRef.")
}
do {
let errSecItemInvalidValue: OSStatus = -34002
let status = Status(rawValue: errSecItemInvalidValue)
XCTAssertEqual(status, .itemInvalidValue)
XCTAssertEqual(status?.description, "A value in a dictionary is an invalid (or unsupported) CF type.")
}
do {
let errSecItemClassMissing: OSStatus = -34003
let status = Status(rawValue: errSecItemClassMissing)
XCTAssertEqual(status, .itemClassMissing)
XCTAssertEqual(status?.description, "No kSecItemClass key was specified in a dictionary.")
}
do {
let errSecItemMatchUnsupported: OSStatus = -34004
let status = Status(rawValue: errSecItemMatchUnsupported)
XCTAssertEqual(status, .itemMatchUnsupported)
XCTAssertEqual(status?.description, "The caller passed one or more kSecMatch keys to a function which does not support matches.")
}
do {
let errSecUseItemListUnsupported: OSStatus = -34005
let status = Status(rawValue: errSecUseItemListUnsupported)
XCTAssertEqual(status, .useItemListUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecUseItemList key to a function which does not support it.")
}
do {
let errSecUseKeychainUnsupported: OSStatus = -34006
let status = Status(rawValue: errSecUseKeychainUnsupported)
XCTAssertEqual(status, .useKeychainUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecUseKeychain key to a function which does not support it.")
}
do {
let errSecUseKeychainListUnsupported: OSStatus = -34007
let status = Status(rawValue: errSecUseKeychainListUnsupported)
XCTAssertEqual(status, .useKeychainListUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecUseKeychainList key to a function which does not support it.")
}
do {
let errSecReturnDataUnsupported: OSStatus = -34008
let status = Status(rawValue: errSecReturnDataUnsupported)
XCTAssertEqual(status, .returnDataUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnData key to a function which does not support it.")
}
do {
let errSecReturnAttributesUnsupported: OSStatus = -34009
let status = Status(rawValue: errSecReturnAttributesUnsupported)
XCTAssertEqual(status, .returnAttributesUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnAttributes key to a function which does not support it.")
}
do {
let errSecReturnRefUnsupported: OSStatus = -34010
let status = Status(rawValue: errSecReturnRefUnsupported)
XCTAssertEqual(status, .returnRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnRef key to a function which does not support it.")
}
do {
let errSecReturnPersitentRefUnsupported: OSStatus = -34011
let status = Status(rawValue: errSecReturnPersitentRefUnsupported)
XCTAssertEqual(status, .returnPersitentRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecReturnPersistentRef key to a function which does not support it.")
}
do {
let errSecValueRefUnsupported: OSStatus = -34012
let status = Status(rawValue: errSecValueRefUnsupported)
XCTAssertEqual(status, .valueRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecValueRef key to a function which does not support it.")
}
do {
let errSecValuePersistentRefUnsupported: OSStatus = -34013
let status = Status(rawValue: errSecValuePersistentRefUnsupported)
XCTAssertEqual(status, .valuePersistentRefUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecValuePersistentRef key to a function which does not support it.")
}
do {
let errSecReturnMissingPointer: OSStatus = -34014
let status = Status(rawValue: errSecReturnMissingPointer)
XCTAssertEqual(status, .returnMissingPointer)
XCTAssertEqual(status?.description, "The caller passed asked for something to be returned but did not pass in a result pointer.")
}
do {
let errSecMatchLimitUnsupported: OSStatus = -34015
let status = Status(rawValue: errSecMatchLimitUnsupported)
XCTAssertEqual(status, .matchLimitUnsupported)
XCTAssertEqual(status?.description, "The caller passed in a kSecMatchLimit key to a call which does not support limits.")
}
do {
let errSecItemIllegalQuery: OSStatus = -34016
let status = Status(rawValue: errSecItemIllegalQuery)
XCTAssertEqual(status, .itemIllegalQuery)
XCTAssertEqual(status?.description, "The caller passed in a query which contained too many keys.")
}
do {
let errSecWaitForCallback: OSStatus = -34017
let status = Status(rawValue: errSecWaitForCallback)
XCTAssertEqual(status, .waitForCallback)
XCTAssertEqual(status?.description, "This operation is incomplete, until the callback is invoked (not an error).")
}
do {
let errSecMissingEntitlement: OSStatus = -34018
let status = Status(rawValue: errSecMissingEntitlement)
XCTAssertEqual(status, .missingEntitlement)
XCTAssertEqual(status?.description, "Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements.")
}
do {
let errSecUpgradePending: OSStatus = -34019
let status = Status(rawValue: errSecUpgradePending)
XCTAssertEqual(status, .upgradePending)
XCTAssertEqual(status?.description, "Error returned if keychain database needs a schema migration but the device is locked, clients should wait for a device unlock notification and retry the command.")
}
do {
let errSecMPSignatureInvalid: OSStatus = -25327
let status = Status(rawValue: errSecMPSignatureInvalid)
XCTAssertEqual(status, .mpSignatureInvalid)
XCTAssertEqual(status?.description, "Signature invalid on MP message")
}
do {
let errSecOTRTooOld: OSStatus = -25328
let status = Status(rawValue: errSecOTRTooOld)
XCTAssertEqual(status, .otrTooOld)
XCTAssertEqual(status?.description, "Message is too old to use")
}
do {
let errSecOTRIDTooNew: OSStatus = -25329
let status = Status(rawValue: errSecOTRIDTooNew)
XCTAssertEqual(status, .otrIDTooNew)
XCTAssertEqual(status?.description, "Key ID is too new to use! Message from the future?")
}
do {
let status = Status(rawValue: errSecInsufficientClientID)
XCTAssertEqual(status, .insufficientClientID)
XCTAssertEqual(status?.description, "The client ID is not correct.")
}
do {
let status = Status(rawValue: errSecDeviceReset)
XCTAssertEqual(status, .deviceReset)
XCTAssertEqual(status?.description, "A device reset has occurred.")
}
do {
let status = Status(rawValue: errSecDeviceFailed)
XCTAssertEqual(status, .deviceFailed)
XCTAssertEqual(status?.description, "A device failure has occurred.")
}
do {
let status = Status(rawValue: errSecAppleAddAppACLSubject)
XCTAssertEqual(status, .appleAddAppACLSubject)
XCTAssertEqual(status?.description, "Adding an application ACL subject failed.")
}
do {
let status = Status(rawValue: errSecApplePublicKeyIncomplete)
XCTAssertEqual(status, .applePublicKeyIncomplete)
XCTAssertEqual(status?.description, "The public key is incomplete.")
}
do {
let status = Status(rawValue: errSecAppleSignatureMismatch)
XCTAssertEqual(status, .appleSignatureMismatch)
XCTAssertEqual(status?.description, "A signature mismatch has occurred.")
}
do {
let status = Status(rawValue: errSecAppleInvalidKeyStartDate)
XCTAssertEqual(status, .appleInvalidKeyStartDate)
XCTAssertEqual(status?.description, "The specified key has an invalid start date.")
}
do {
let status = Status(rawValue: errSecAppleInvalidKeyEndDate)
XCTAssertEqual(status, .appleInvalidKeyEndDate)
XCTAssertEqual(status?.description, "The specified key has an invalid end date.")
}
do {
let status = Status(rawValue: errSecConversionError)
XCTAssertEqual(status, .conversionError)
XCTAssertEqual(status?.description, "A conversion error has occurred.")
}
do {
let status = Status(rawValue: errSecAppleSSLv2Rollback)
XCTAssertEqual(status, .appleSSLv2Rollback)
XCTAssertEqual(status?.description, "A SSLv2 rollback error has occurred.")
}
do {
let status = Status(rawValue: errSecDiskFull)
XCTAssertEqual(status, .diskFull)
XCTAssertEqual(status?.description, "The disk is full.")
}
do {
let status = Status(rawValue: errSecQuotaExceeded)
XCTAssertEqual(status, .quotaExceeded)
XCTAssertEqual(status?.description, "The quota was exceeded.")
}
do {
let status = Status(rawValue: errSecFileTooBig)
XCTAssertEqual(status, .fileTooBig)
XCTAssertEqual(status?.description, "The file is too big.")
}
do {
let status = Status(rawValue: errSecInvalidDatabaseBlob)
XCTAssertEqual(status, .invalidDatabaseBlob)
XCTAssertEqual(status?.description, "The specified database has an invalid blob.")
}
do {
let status = Status(rawValue: errSecInvalidKeyBlob)
XCTAssertEqual(status, .invalidKeyBlob)
XCTAssertEqual(status?.description, "The specified database has an invalid key blob.")
}
do {
let status = Status(rawValue: errSecIncompatibleDatabaseBlob)
XCTAssertEqual(status, .incompatibleDatabaseBlob)
XCTAssertEqual(status?.description, "The specified database has an incompatible blob.")
}
do {
let status = Status(rawValue: errSecIncompatibleKeyBlob)
XCTAssertEqual(status, .incompatibleKeyBlob)
XCTAssertEqual(status?.description, "The specified database has an incompatible key blob.")
}
do {
let status = Status(rawValue: errSecHostNameMismatch)
XCTAssertEqual(status, .hostNameMismatch)
XCTAssertEqual(status?.description, "A host name mismatch has occurred.")
}
do {
let status = Status(rawValue: errSecUnknownCriticalExtensionFlag)
XCTAssertEqual(status, .unknownCriticalExtensionFlag)
XCTAssertEqual(status?.description, "There is an unknown critical extension flag.")
}
do {
let status = Status(rawValue: errSecNoBasicConstraints)
XCTAssertEqual(status, .noBasicConstraints)
XCTAssertEqual(status?.description, "No basic constraints were found.")
}
do {
let status = Status(rawValue: errSecNoBasicConstraintsCA)
XCTAssertEqual(status, .noBasicConstraintsCA)
XCTAssertEqual(status?.description, "No basic CA constraints were found.")
}
do {
let status = Status(rawValue: errSecInvalidAuthorityKeyID)
XCTAssertEqual(status, .invalidAuthorityKeyID)
XCTAssertEqual(status?.description, "The authority key ID is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidSubjectKeyID)
XCTAssertEqual(status, .invalidSubjectKeyID)
XCTAssertEqual(status?.description, "The subject key ID is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidKeyUsageForPolicy)
XCTAssertEqual(status, .invalidKeyUsageForPolicy)
XCTAssertEqual(status?.description, "The key usage is not valid for the specified policy.")
}
do {
let status = Status(rawValue: errSecInvalidExtendedKeyUsage)
XCTAssertEqual(status, .invalidExtendedKeyUsage)
XCTAssertEqual(status?.description, "The extended key usage is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIDLinkage)
XCTAssertEqual(status, .invalidIDLinkage)
XCTAssertEqual(status?.description, "The ID linkage is not valid.")
}
do {
let status = Status(rawValue: errSecPathLengthConstraintExceeded)
XCTAssertEqual(status, .pathLengthConstraintExceeded)
XCTAssertEqual(status?.description, "The path length constraint was exceeded.")
}
do {
let status = Status(rawValue: errSecInvalidRoot)
XCTAssertEqual(status, .invalidRoot)
XCTAssertEqual(status?.description, "The root or anchor certificate is not valid.")
}
do {
let status = Status(rawValue: errSecCRLExpired)
XCTAssertEqual(status, .crlExpired)
XCTAssertEqual(status?.description, "The CRL has expired.")
}
do {
let status = Status(rawValue: errSecCRLNotValidYet)
XCTAssertEqual(status, .crlNotValidYet)
XCTAssertEqual(status?.description, "The CRL is not yet valid.")
}
do {
let status = Status(rawValue: errSecCRLNotFound)
XCTAssertEqual(status, .crlNotFound)
XCTAssertEqual(status?.description, "The CRL was not found.")
}
do {
let status = Status(rawValue: errSecCRLServerDown)
XCTAssertEqual(status, .crlServerDown)
XCTAssertEqual(status?.description, "The CRL server is down.")
}
do {
let status = Status(rawValue: errSecCRLBadURI)
XCTAssertEqual(status, .crlBadURI)
XCTAssertEqual(status?.description, "The CRL has a bad Uniform Resource Identifier.")
}
do {
let status = Status(rawValue: errSecUnknownCertExtension)
XCTAssertEqual(status, .unknownCertExtension)
XCTAssertEqual(status?.description, "An unknown certificate extension was encountered.")
}
do {
let status = Status(rawValue: errSecUnknownCRLExtension)
XCTAssertEqual(status, .unknownCRLExtension)
XCTAssertEqual(status?.description, "An unknown CRL extension was encountered.")
}
do {
let status = Status(rawValue: errSecCRLNotTrusted)
XCTAssertEqual(status, .crlNotTrusted)
XCTAssertEqual(status?.description, "The CRL is not trusted.")
}
do {
let status = Status(rawValue: errSecCRLPolicyFailed)
XCTAssertEqual(status, .crlPolicyFailed)
XCTAssertEqual(status?.description, "The CRL policy failed.")
}
do {
let status = Status(rawValue: errSecIDPFailure)
XCTAssertEqual(status, .idpFailure)
XCTAssertEqual(status?.description, "The issuing distribution point was not valid.")
}
do {
let status = Status(rawValue: errSecSMIMEEmailAddressesNotFound)
XCTAssertEqual(status, .smimeEmailAddressesNotFound)
XCTAssertEqual(status?.description, "An email address mismatch was encountered.")
}
do {
let status = Status(rawValue: errSecSMIMEBadExtendedKeyUsage)
XCTAssertEqual(status, .smimeBadExtendedKeyUsage)
XCTAssertEqual(status?.description, "The appropriate extended key usage for SMIME was not found.")
}
do {
let status = Status(rawValue: errSecSMIMEBadKeyUsage)
XCTAssertEqual(status, .smimeBadKeyUsage)
XCTAssertEqual(status?.description, "The key usage is not compatible with SMIME.")
}
do {
let status = Status(rawValue: errSecSMIMEKeyUsageNotCritical)
XCTAssertEqual(status, .smimeKeyUsageNotCritical)
XCTAssertEqual(status?.description, "The key usage extension is not marked as critical.")
}
do {
let status = Status(rawValue: errSecSMIMENoEmailAddress)
XCTAssertEqual(status, .smimeNoEmailAddress)
XCTAssertEqual(status?.description, "No email address was found in the certificate.")
}
do {
let status = Status(rawValue: errSecSMIMESubjAltNameNotCritical)
XCTAssertEqual(status, .smimeSubjAltNameNotCritical)
XCTAssertEqual(status?.description, "The subject alternative name extension is not marked as critical.")
}
do {
let status = Status(rawValue: errSecSSLBadExtendedKeyUsage)
XCTAssertEqual(status, .sslBadExtendedKeyUsage)
XCTAssertEqual(status?.description, "The appropriate extended key usage for SSL was not found.")
}
do {
let status = Status(rawValue: errSecOCSPBadResponse)
XCTAssertEqual(status, .ocspBadResponse)
XCTAssertEqual(status?.description, "The OCSP response was incorrect or could not be parsed.")
}
do {
let status = Status(rawValue: errSecOCSPBadRequest)
XCTAssertEqual(status, .ocspBadRequest)
XCTAssertEqual(status?.description, "The OCSP request was incorrect or could not be parsed.")
}
do {
let status = Status(rawValue: errSecOCSPUnavailable)
XCTAssertEqual(status, .ocspUnavailable)
XCTAssertEqual(status?.description, "OCSP service is unavailable.")
}
do {
let status = Status(rawValue: errSecOCSPStatusUnrecognized)
XCTAssertEqual(status, .ocspStatusUnrecognized)
XCTAssertEqual(status?.description, "The OCSP server did not recognize this certificate.")
}
do {
let status = Status(rawValue: errSecEndOfData)
XCTAssertEqual(status, .endOfData)
XCTAssertEqual(status?.description, "An end-of-data was detected.")
}
do {
let status = Status(rawValue: errSecIncompleteCertRevocationCheck)
XCTAssertEqual(status, .incompleteCertRevocationCheck)
XCTAssertEqual(status?.description, "An incomplete certificate revocation check occurred.")
}
do {
let status = Status(rawValue: errSecNetworkFailure)
XCTAssertEqual(status, .networkFailure)
XCTAssertEqual(status?.description, "A network failure occurred.")
}
do {
let status = Status(rawValue: errSecOCSPNotTrustedToAnchor)
XCTAssertEqual(status, .ocspNotTrustedToAnchor)
XCTAssertEqual(status?.description, "The OCSP response was not trusted to a root or anchor certificate.")
}
do {
let status = Status(rawValue: errSecRecordModified)
XCTAssertEqual(status, .recordModified)
XCTAssertEqual(status?.description, "The record was modified.")
}
do {
let status = Status(rawValue: errSecOCSPSignatureError)
XCTAssertEqual(status, .ocspSignatureError)
XCTAssertEqual(status?.description, "The OCSP response had an invalid signature.")
}
do {
let status = Status(rawValue: errSecOCSPNoSigner)
XCTAssertEqual(status, .ocspNoSigner)
XCTAssertEqual(status?.description, "The OCSP response had no signer.")
}
do {
let status = Status(rawValue: errSecOCSPResponderMalformedReq)
XCTAssertEqual(status, .ocspResponderMalformedReq)
XCTAssertEqual(status?.description, "The OCSP responder was given a malformed request.")
}
do {
let status = Status(rawValue: errSecOCSPResponderInternalError)
XCTAssertEqual(status, .ocspResponderInternalError)
XCTAssertEqual(status?.description, "The OCSP responder encountered an internal error.")
}
do {
let status = Status(rawValue: errSecOCSPResponderTryLater)
XCTAssertEqual(status, .ocspResponderTryLater)
XCTAssertEqual(status?.description, "The OCSP responder is busy, try again later.")
}
do {
let status = Status(rawValue: errSecOCSPResponderSignatureRequired)
XCTAssertEqual(status, .ocspResponderSignatureRequired)
XCTAssertEqual(status?.description, "The OCSP responder requires a signature.")
}
do {
let status = Status(rawValue: errSecOCSPResponderUnauthorized)
XCTAssertEqual(status, .ocspResponderUnauthorized)
XCTAssertEqual(status?.description, "The OCSP responder rejected this request as unauthorized.")
}
do {
let status = Status(rawValue: errSecOCSPResponseNonceMismatch)
XCTAssertEqual(status, .ocspResponseNonceMismatch)
XCTAssertEqual(status?.description, "The OCSP response nonce did not match the request.")
}
do {
let status = Status(rawValue: errSecCodeSigningBadCertChainLength)
XCTAssertEqual(status, .codeSigningBadCertChainLength)
XCTAssertEqual(status?.description, "Code signing encountered an incorrect certificate chain length.")
}
do {
let status = Status(rawValue: errSecCodeSigningNoBasicConstraints)
XCTAssertEqual(status, .codeSigningNoBasicConstraints)
XCTAssertEqual(status?.description, "Code signing found no basic constraints.")
}
do {
let status = Status(rawValue: errSecCodeSigningBadPathLengthConstraint)
XCTAssertEqual(status, .codeSigningBadPathLengthConstraint)
XCTAssertEqual(status?.description, "Code signing encountered an incorrect path length constraint.")
}
do {
let status = Status(rawValue: errSecCodeSigningNoExtendedKeyUsage)
XCTAssertEqual(status, .codeSigningNoExtendedKeyUsage)
XCTAssertEqual(status?.description, "Code signing found no extended key usage.")
}
do {
let status = Status(rawValue: errSecCodeSigningDevelopment)
XCTAssertEqual(status, .codeSigningDevelopment)
XCTAssertEqual(status?.description, "Code signing indicated use of a development-only certificate.")
}
do {
let status = Status(rawValue: errSecResourceSignBadCertChainLength)
XCTAssertEqual(status, .resourceSignBadCertChainLength)
XCTAssertEqual(status?.description, "Resource signing has encountered an incorrect certificate chain length.")
}
do {
let status = Status(rawValue: errSecResourceSignBadExtKeyUsage)
XCTAssertEqual(status, .resourceSignBadExtKeyUsage)
XCTAssertEqual(status?.description, "Resource signing has encountered an error in the extended key usage.")
}
do {
let status = Status(rawValue: errSecTrustSettingDeny)
XCTAssertEqual(status, .trustSettingDeny)
XCTAssertEqual(status?.description, "The trust setting for this policy was set to Deny.")
}
do {
let status = Status(rawValue: errSecInvalidSubjectName)
XCTAssertEqual(status, .invalidSubjectName)
XCTAssertEqual(status?.description, "An invalid certificate subject name was encountered.")
}
do {
let status = Status(rawValue: errSecUnknownQualifiedCertStatement)
XCTAssertEqual(status, .unknownQualifiedCertStatement)
XCTAssertEqual(status?.description, "An unknown qualified certificate statement was encountered.")
}
do {
let status = Status(rawValue: errSecMobileMeRequestQueued)
XCTAssertEqual(status, .mobileMeRequestQueued)
XCTAssertEqual(status?.description, "The MobileMe request will be sent during the next connection.")
}
do {
let status = Status(rawValue: errSecMobileMeRequestRedirected)
XCTAssertEqual(status, .mobileMeRequestRedirected)
XCTAssertEqual(status?.description, "The MobileMe request was redirected.")
}
do {
let status = Status(rawValue: errSecMobileMeServerError)
XCTAssertEqual(status, .mobileMeServerError)
XCTAssertEqual(status?.description, "A MobileMe server error occurred.")
}
do {
let status = Status(rawValue: errSecMobileMeServerNotAvailable)
XCTAssertEqual(status, .mobileMeServerNotAvailable)
XCTAssertEqual(status?.description, "The MobileMe server is not available.")
}
do {
let status = Status(rawValue: errSecMobileMeServerAlreadyExists)
XCTAssertEqual(status, .mobileMeServerAlreadyExists)
XCTAssertEqual(status?.description, "The MobileMe server reported that the item already exists.")
}
do {
let status = Status(rawValue: errSecMobileMeServerServiceErr)
XCTAssertEqual(status, .mobileMeServerServiceErr)
XCTAssertEqual(status?.description, "A MobileMe service error has occurred.")
}
do {
let status = Status(rawValue: errSecMobileMeRequestAlreadyPending)
XCTAssertEqual(status, .mobileMeRequestAlreadyPending)
XCTAssertEqual(status?.description, "A MobileMe request is already pending.")
}
do {
let status = Status(rawValue: errSecMobileMeNoRequestPending)
XCTAssertEqual(status, .mobileMeNoRequestPending)
XCTAssertEqual(status?.description, "MobileMe has no request pending.")
}
do {
let status = Status(rawValue: errSecMobileMeCSRVerifyFailure)
XCTAssertEqual(status, .mobileMeCSRVerifyFailure)
XCTAssertEqual(status?.description, "A MobileMe CSR verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecMobileMeFailedConsistencyCheck)
XCTAssertEqual(status, .mobileMeFailedConsistencyCheck)
XCTAssertEqual(status?.description, "MobileMe has found a failed consistency check.")
}
do {
let status = Status(rawValue: errSecNotInitialized)
XCTAssertEqual(status, .notInitialized)
XCTAssertEqual(status?.description, "A function was called without initializing CSSM.")
}
do {
let status = Status(rawValue: errSecInvalidHandleUsage)
XCTAssertEqual(status, .invalidHandleUsage)
XCTAssertEqual(status?.description, "The CSSM handle does not match with the service type.")
}
do {
let status = Status(rawValue: errSecPVCReferentNotFound)
XCTAssertEqual(status, .pvcReferentNotFound)
XCTAssertEqual(status?.description, "A reference to the calling module was not found in the list of authorized callers.")
}
do {
let status = Status(rawValue: errSecFunctionIntegrityFail)
XCTAssertEqual(status, .functionIntegrityFail)
XCTAssertEqual(status?.description, "A function address was not within the verified module.")
}
do {
let status = Status(rawValue: errSecInternalError)
XCTAssertEqual(status, .internalError)
XCTAssertEqual(status?.description, "An internal error has occurred.")
}
do {
let status = Status(rawValue: errSecMemoryError)
XCTAssertEqual(status, .memoryError)
XCTAssertEqual(status?.description, "A memory error has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidData)
XCTAssertEqual(status, .invalidData)
XCTAssertEqual(status?.description, "Invalid data was encountered.")
}
do {
let status = Status(rawValue: errSecMDSError)
XCTAssertEqual(status, .mdsError)
XCTAssertEqual(status?.description, "A Module Directory Service error has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidPointer)
XCTAssertEqual(status, .invalidPointer)
XCTAssertEqual(status?.description, "An invalid pointer was encountered.")
}
do {
let status = Status(rawValue: errSecSelfCheckFailed)
XCTAssertEqual(status, .selfCheckFailed)
XCTAssertEqual(status?.description, "Self-check has failed.")
}
do {
let status = Status(rawValue: errSecFunctionFailed)
XCTAssertEqual(status, .functionFailed)
XCTAssertEqual(status?.description, "A function has failed.")
}
do {
let status = Status(rawValue: errSecModuleManifestVerifyFailed)
XCTAssertEqual(status, .moduleManifestVerifyFailed)
XCTAssertEqual(status?.description, "A module manifest verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidGUID)
XCTAssertEqual(status, .invalidGUID)
XCTAssertEqual(status?.description, "An invalid GUID was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidHandle)
XCTAssertEqual(status, .invalidHandle)
XCTAssertEqual(status?.description, "An invalid handle was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidDBList)
XCTAssertEqual(status, .invalidDBList)
XCTAssertEqual(status?.description, "An invalid DB list was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidPassthroughID)
XCTAssertEqual(status, .invalidPassthroughID)
XCTAssertEqual(status?.description, "An invalid passthrough ID was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidNetworkAddress)
XCTAssertEqual(status, .invalidNetworkAddress)
XCTAssertEqual(status?.description, "An invalid network address was encountered.")
}
do {
let status = Status(rawValue: errSecCRLAlreadySigned)
XCTAssertEqual(status, .crlAlreadySigned)
XCTAssertEqual(status?.description, "The certificate revocation list is already signed.")
}
do {
let status = Status(rawValue: errSecInvalidNumberOfFields)
XCTAssertEqual(status, .invalidNumberOfFields)
XCTAssertEqual(status?.description, "An invalid number of fields were encountered.")
}
do {
let status = Status(rawValue: errSecVerificationFailure)
XCTAssertEqual(status, .verificationFailure)
XCTAssertEqual(status?.description, "A verification failure occurred.")
}
do {
let status = Status(rawValue: errSecUnknownTag)
XCTAssertEqual(status, .unknownTag)
XCTAssertEqual(status?.description, "An unknown tag was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidSignature)
XCTAssertEqual(status, .invalidSignature)
XCTAssertEqual(status?.description, "An invalid signature was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidName)
XCTAssertEqual(status, .invalidName)
XCTAssertEqual(status?.description, "An invalid name was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidCertificateRef)
XCTAssertEqual(status, .invalidCertificateRef)
XCTAssertEqual(status?.description, "An invalid certificate reference was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidCertificateGroup)
XCTAssertEqual(status, .invalidCertificateGroup)
XCTAssertEqual(status?.description, "An invalid certificate group was encountered.")
}
do {
let status = Status(rawValue: errSecTagNotFound)
XCTAssertEqual(status, .tagNotFound)
XCTAssertEqual(status?.description, "The specified tag was not found.")
}
do {
let status = Status(rawValue: errSecInvalidQuery)
XCTAssertEqual(status, .invalidQuery)
XCTAssertEqual(status?.description, "The specified query was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidValue)
XCTAssertEqual(status, .invalidValue)
XCTAssertEqual(status?.description, "An invalid value was detected.")
}
do {
let status = Status(rawValue: errSecCallbackFailed)
XCTAssertEqual(status, .callbackFailed)
XCTAssertEqual(status?.description, "A callback has failed.")
}
do {
let status = Status(rawValue: errSecACLDeleteFailed)
XCTAssertEqual(status, .aclDeleteFailed)
XCTAssertEqual(status?.description, "An ACL delete operation has failed.")
}
do {
let status = Status(rawValue: errSecACLReplaceFailed)
XCTAssertEqual(status, .aclReplaceFailed)
XCTAssertEqual(status?.description, "An ACL replace operation has failed.")
}
do {
let status = Status(rawValue: errSecACLAddFailed)
XCTAssertEqual(status, .aclAddFailed)
XCTAssertEqual(status?.description, "An ACL add operation has failed.")
}
do {
let status = Status(rawValue: errSecACLChangeFailed)
XCTAssertEqual(status, .aclChangeFailed)
XCTAssertEqual(status?.description, "An ACL change operation has failed.")
}
do {
let status = Status(rawValue: errSecInvalidAccessCredentials)
XCTAssertEqual(status, .invalidAccessCredentials)
XCTAssertEqual(status?.description, "Invalid access credentials were encountered.")
}
do {
let status = Status(rawValue: errSecInvalidRecord)
XCTAssertEqual(status, .invalidRecord)
XCTAssertEqual(status?.description, "An invalid record was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidACL)
XCTAssertEqual(status, .invalidACL)
XCTAssertEqual(status?.description, "An invalid ACL was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidSampleValue)
XCTAssertEqual(status, .invalidSampleValue)
XCTAssertEqual(status?.description, "An invalid sample value was encountered.")
}
do {
let status = Status(rawValue: errSecIncompatibleVersion)
XCTAssertEqual(status, .incompatibleVersion)
XCTAssertEqual(status?.description, "An incompatible version was encountered.")
}
do {
let status = Status(rawValue: errSecPrivilegeNotGranted)
XCTAssertEqual(status, .privilegeNotGranted)
XCTAssertEqual(status?.description, "The privilege was not granted.")
}
do {
let status = Status(rawValue: errSecInvalidScope)
XCTAssertEqual(status, .invalidScope)
XCTAssertEqual(status?.description, "An invalid scope was encountered.")
}
do {
let status = Status(rawValue: errSecPVCAlreadyConfigured)
XCTAssertEqual(status, .pvcAlreadyConfigured)
XCTAssertEqual(status?.description, "The PVC is already configured.")
}
do {
let status = Status(rawValue: errSecInvalidPVC)
XCTAssertEqual(status, .invalidPVC)
XCTAssertEqual(status?.description, "An invalid PVC was encountered.")
}
do {
let status = Status(rawValue: errSecEMMLoadFailed)
XCTAssertEqual(status, .emmLoadFailed)
XCTAssertEqual(status?.description, "The EMM load has failed.")
}
do {
let status = Status(rawValue: errSecEMMUnloadFailed)
XCTAssertEqual(status, .emmUnloadFailed)
XCTAssertEqual(status?.description, "The EMM unload has failed.")
}
do {
let status = Status(rawValue: errSecAddinLoadFailed)
XCTAssertEqual(status, .addinLoadFailed)
XCTAssertEqual(status?.description, "The add-in load operation has failed.")
}
do {
let status = Status(rawValue: errSecInvalidKeyRef)
XCTAssertEqual(status, .invalidKeyRef)
XCTAssertEqual(status?.description, "An invalid key was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidKeyHierarchy)
XCTAssertEqual(status, .invalidKeyHierarchy)
XCTAssertEqual(status?.description, "An invalid key hierarchy was encountered.")
}
do {
let status = Status(rawValue: errSecAddinUnloadFailed)
XCTAssertEqual(status, .addinUnloadFailed)
XCTAssertEqual(status?.description, "The add-in unload operation has failed.")
}
do {
let status = Status(rawValue: errSecLibraryReferenceNotFound)
XCTAssertEqual(status, .libraryReferenceNotFound)
XCTAssertEqual(status?.description, "A library reference was not found.")
}
do {
let status = Status(rawValue: errSecInvalidAddinFunctionTable)
XCTAssertEqual(status, .invalidAddinFunctionTable)
XCTAssertEqual(status?.description, "An invalid add-in function table was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidServiceMask)
XCTAssertEqual(status, .invalidServiceMask)
XCTAssertEqual(status?.description, "An invalid service mask was encountered.")
}
do {
let status = Status(rawValue: errSecModuleNotLoaded)
XCTAssertEqual(status, .moduleNotLoaded)
XCTAssertEqual(status?.description, "A module was not loaded.")
}
do {
let status = Status(rawValue: errSecInvalidSubServiceID)
XCTAssertEqual(status, .invalidSubServiceID)
XCTAssertEqual(status?.description, "An invalid subservice ID was encountered.")
}
do {
let status = Status(rawValue: errSecAttributeNotInContext)
XCTAssertEqual(status, .attributeNotInContext)
XCTAssertEqual(status?.description, "An attribute was not in the context.")
}
do {
let status = Status(rawValue: errSecModuleManagerInitializeFailed)
XCTAssertEqual(status, .moduleManagerInitializeFailed)
XCTAssertEqual(status?.description, "A module failed to initialize.")
}
do {
let status = Status(rawValue: errSecModuleManagerNotFound)
XCTAssertEqual(status, .moduleManagerNotFound)
XCTAssertEqual(status?.description, "A module was not found.")
}
do {
let status = Status(rawValue: errSecEventNotificationCallbackNotFound)
XCTAssertEqual(status, .eventNotificationCallbackNotFound)
XCTAssertEqual(status?.description, "An event notification callback was not found.")
}
do {
let status = Status(rawValue: errSecInputLengthError)
XCTAssertEqual(status, .inputLengthError)
XCTAssertEqual(status?.description, "An input length error was encountered.")
}
do {
let status = Status(rawValue: errSecOutputLengthError)
XCTAssertEqual(status, .outputLengthError)
XCTAssertEqual(status?.description, "An output length error was encountered.")
}
do {
let status = Status(rawValue: errSecPrivilegeNotSupported)
XCTAssertEqual(status, .privilegeNotSupported)
XCTAssertEqual(status?.description, "The privilege is not supported.")
}
do {
let status = Status(rawValue: errSecDeviceError)
XCTAssertEqual(status, .deviceError)
XCTAssertEqual(status?.description, "A device error was encountered.")
}
do {
let status = Status(rawValue: errSecAttachHandleBusy)
XCTAssertEqual(status, .attachHandleBusy)
XCTAssertEqual(status?.description, "The CSP handle was busy.")
}
do {
let status = Status(rawValue: errSecNotLoggedIn)
XCTAssertEqual(status, .notLoggedIn)
XCTAssertEqual(status?.description, "You are not logged in.")
}
do {
let status = Status(rawValue: errSecAlgorithmMismatch)
XCTAssertEqual(status, .algorithmMismatch)
XCTAssertEqual(status?.description, "An algorithm mismatch was encountered.")
}
do {
let status = Status(rawValue: errSecKeyUsageIncorrect)
XCTAssertEqual(status, .keyUsageIncorrect)
XCTAssertEqual(status?.description, "The key usage is incorrect.")
}
do {
let status = Status(rawValue: errSecKeyBlobTypeIncorrect)
XCTAssertEqual(status, .keyBlobTypeIncorrect)
XCTAssertEqual(status?.description, "The key blob type is incorrect.")
}
do {
let status = Status(rawValue: errSecKeyHeaderInconsistent)
XCTAssertEqual(status, .keyHeaderInconsistent)
XCTAssertEqual(status?.description, "The key header is inconsistent.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyFormat)
XCTAssertEqual(status, .unsupportedKeyFormat)
XCTAssertEqual(status?.description, "The key header format is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeySize)
XCTAssertEqual(status, .unsupportedKeySize)
XCTAssertEqual(status?.description, "The key size is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyUsageMask)
XCTAssertEqual(status, .invalidKeyUsageMask)
XCTAssertEqual(status?.description, "The key usage mask is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyUsageMask)
XCTAssertEqual(status, .unsupportedKeyUsageMask)
XCTAssertEqual(status?.description, "The key usage mask is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyAttributeMask)
XCTAssertEqual(status, .invalidKeyAttributeMask)
XCTAssertEqual(status?.description, "The key attribute mask is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyAttributeMask)
XCTAssertEqual(status, .unsupportedKeyAttributeMask)
XCTAssertEqual(status?.description, "The key attribute mask is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyLabel)
XCTAssertEqual(status, .invalidKeyLabel)
XCTAssertEqual(status?.description, "The key label is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedKeyLabel)
XCTAssertEqual(status, .unsupportedKeyLabel)
XCTAssertEqual(status?.description, "The key label is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidKeyFormat)
XCTAssertEqual(status, .invalidKeyFormat)
XCTAssertEqual(status?.description, "The key format is not valid.")
}
do {
let status = Status(rawValue: errSecUnsupportedVectorOfBuffers)
XCTAssertEqual(status, .unsupportedVectorOfBuffers)
XCTAssertEqual(status?.description, "The vector of buffers is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidInputVector)
XCTAssertEqual(status, .invalidInputVector)
XCTAssertEqual(status?.description, "The input vector is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidOutputVector)
XCTAssertEqual(status, .invalidOutputVector)
XCTAssertEqual(status?.description, "The output vector is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidContext)
XCTAssertEqual(status, .invalidContext)
XCTAssertEqual(status?.description, "An invalid context was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidAlgorithm)
XCTAssertEqual(status, .invalidAlgorithm)
XCTAssertEqual(status?.description, "An invalid algorithm was encountered.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeKey)
XCTAssertEqual(status, .invalidAttributeKey)
XCTAssertEqual(status?.description, "A key attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeKey)
XCTAssertEqual(status, .missingAttributeKey)
XCTAssertEqual(status?.description, "A key attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeInitVector)
XCTAssertEqual(status, .invalidAttributeInitVector)
XCTAssertEqual(status?.description, "An init vector attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeInitVector)
XCTAssertEqual(status, .missingAttributeInitVector)
XCTAssertEqual(status?.description, "An init vector attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSalt)
XCTAssertEqual(status, .invalidAttributeSalt)
XCTAssertEqual(status?.description, "A salt attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSalt)
XCTAssertEqual(status, .missingAttributeSalt)
XCTAssertEqual(status?.description, "A salt attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePadding)
XCTAssertEqual(status, .invalidAttributePadding)
XCTAssertEqual(status?.description, "A padding attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePadding)
XCTAssertEqual(status, .missingAttributePadding)
XCTAssertEqual(status?.description, "A padding attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeRandom)
XCTAssertEqual(status, .invalidAttributeRandom)
XCTAssertEqual(status?.description, "A random number attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeRandom)
XCTAssertEqual(status, .missingAttributeRandom)
XCTAssertEqual(status?.description, "A random number attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSeed)
XCTAssertEqual(status, .invalidAttributeSeed)
XCTAssertEqual(status?.description, "A seed attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSeed)
XCTAssertEqual(status, .missingAttributeSeed)
XCTAssertEqual(status?.description, "A seed attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePassphrase)
XCTAssertEqual(status, .invalidAttributePassphrase)
XCTAssertEqual(status?.description, "A passphrase attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePassphrase)
XCTAssertEqual(status, .missingAttributePassphrase)
XCTAssertEqual(status?.description, "A passphrase attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeKeyLength)
XCTAssertEqual(status, .invalidAttributeKeyLength)
XCTAssertEqual(status?.description, "A key length attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeKeyLength)
XCTAssertEqual(status, .missingAttributeKeyLength)
XCTAssertEqual(status?.description, "A key length attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeBlockSize)
XCTAssertEqual(status, .invalidAttributeBlockSize)
XCTAssertEqual(status?.description, "A block size attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeBlockSize)
XCTAssertEqual(status, .missingAttributeBlockSize)
XCTAssertEqual(status?.description, "A block size attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeOutputSize)
XCTAssertEqual(status, .invalidAttributeOutputSize)
XCTAssertEqual(status?.description, "An output size attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeOutputSize)
XCTAssertEqual(status, .missingAttributeOutputSize)
XCTAssertEqual(status?.description, "An output size attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeRounds)
XCTAssertEqual(status, .invalidAttributeRounds)
XCTAssertEqual(status?.description, "The number of rounds attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeRounds)
XCTAssertEqual(status, .missingAttributeRounds)
XCTAssertEqual(status?.description, "The number of rounds attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAlgorithmParms)
XCTAssertEqual(status, .invalidAlgorithmParms)
XCTAssertEqual(status?.description, "An algorithm parameters attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAlgorithmParms)
XCTAssertEqual(status, .missingAlgorithmParms)
XCTAssertEqual(status?.description, "An algorithm parameters attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeLabel)
XCTAssertEqual(status, .invalidAttributeLabel)
XCTAssertEqual(status?.description, "A label attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeLabel)
XCTAssertEqual(status, .missingAttributeLabel)
XCTAssertEqual(status?.description, "A label attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeKeyType)
XCTAssertEqual(status, .invalidAttributeKeyType)
XCTAssertEqual(status?.description, "A key type attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeKeyType)
XCTAssertEqual(status, .missingAttributeKeyType)
XCTAssertEqual(status?.description, "A key type attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeMode)
XCTAssertEqual(status, .invalidAttributeMode)
XCTAssertEqual(status?.description, "A mode attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeMode)
XCTAssertEqual(status, .missingAttributeMode)
XCTAssertEqual(status?.description, "A mode attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeEffectiveBits)
XCTAssertEqual(status, .invalidAttributeEffectiveBits)
XCTAssertEqual(status?.description, "An effective bits attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeEffectiveBits)
XCTAssertEqual(status, .missingAttributeEffectiveBits)
XCTAssertEqual(status?.description, "An effective bits attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeStartDate)
XCTAssertEqual(status, .invalidAttributeStartDate)
XCTAssertEqual(status?.description, "A start date attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeStartDate)
XCTAssertEqual(status, .missingAttributeStartDate)
XCTAssertEqual(status?.description, "A start date attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeEndDate)
XCTAssertEqual(status, .invalidAttributeEndDate)
XCTAssertEqual(status?.description, "An end date attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeEndDate)
XCTAssertEqual(status, .missingAttributeEndDate)
XCTAssertEqual(status?.description, "An end date attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeVersion)
XCTAssertEqual(status, .invalidAttributeVersion)
XCTAssertEqual(status?.description, "A version attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeVersion)
XCTAssertEqual(status, .missingAttributeVersion)
XCTAssertEqual(status?.description, "A version attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePrime)
XCTAssertEqual(status, .invalidAttributePrime)
XCTAssertEqual(status?.description, "A prime attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePrime)
XCTAssertEqual(status, .missingAttributePrime)
XCTAssertEqual(status?.description, "A prime attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeBase)
XCTAssertEqual(status, .invalidAttributeBase)
XCTAssertEqual(status?.description, "A base attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeBase)
XCTAssertEqual(status, .missingAttributeBase)
XCTAssertEqual(status?.description, "A base attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSubprime)
XCTAssertEqual(status, .invalidAttributeSubprime)
XCTAssertEqual(status?.description, "A subprime attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSubprime)
XCTAssertEqual(status, .missingAttributeSubprime)
XCTAssertEqual(status?.description, "A subprime attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeIterationCount)
XCTAssertEqual(status, .invalidAttributeIterationCount)
XCTAssertEqual(status?.description, "An iteration count attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeIterationCount)
XCTAssertEqual(status, .missingAttributeIterationCount)
XCTAssertEqual(status?.description, "An iteration count attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeDLDBHandle)
XCTAssertEqual(status, .invalidAttributeDLDBHandle)
XCTAssertEqual(status?.description, "A database handle attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeDLDBHandle)
XCTAssertEqual(status, .missingAttributeDLDBHandle)
XCTAssertEqual(status?.description, "A database handle attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeAccessCredentials)
XCTAssertEqual(status, .invalidAttributeAccessCredentials)
XCTAssertEqual(status?.description, "An access credentials attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeAccessCredentials)
XCTAssertEqual(status, .missingAttributeAccessCredentials)
XCTAssertEqual(status?.description, "An access credentials attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePublicKeyFormat)
XCTAssertEqual(status, .invalidAttributePublicKeyFormat)
XCTAssertEqual(status?.description, "A public key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePublicKeyFormat)
XCTAssertEqual(status, .missingAttributePublicKeyFormat)
XCTAssertEqual(status?.description, "A public key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributePrivateKeyFormat)
XCTAssertEqual(status, .invalidAttributePrivateKeyFormat)
XCTAssertEqual(status?.description, "A private key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributePrivateKeyFormat)
XCTAssertEqual(status, .missingAttributePrivateKeyFormat)
XCTAssertEqual(status?.description, "A private key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeSymmetricKeyFormat)
XCTAssertEqual(status, .invalidAttributeSymmetricKeyFormat)
XCTAssertEqual(status?.description, "A symmetric key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeSymmetricKeyFormat)
XCTAssertEqual(status, .missingAttributeSymmetricKeyFormat)
XCTAssertEqual(status?.description, "A symmetric key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecInvalidAttributeWrappedKeyFormat)
XCTAssertEqual(status, .invalidAttributeWrappedKeyFormat)
XCTAssertEqual(status?.description, "A wrapped key format attribute was not valid.")
}
do {
let status = Status(rawValue: errSecMissingAttributeWrappedKeyFormat)
XCTAssertEqual(status, .missingAttributeWrappedKeyFormat)
XCTAssertEqual(status?.description, "A wrapped key format attribute was missing.")
}
do {
let status = Status(rawValue: errSecStagedOperationInProgress)
XCTAssertEqual(status, .stagedOperationInProgress)
XCTAssertEqual(status?.description, "A staged operation is in progress.")
}
do {
let status = Status(rawValue: errSecStagedOperationNotStarted)
XCTAssertEqual(status, .stagedOperationNotStarted)
XCTAssertEqual(status?.description, "A staged operation was not started.")
}
do {
let status = Status(rawValue: errSecVerifyFailed)
XCTAssertEqual(status, .verifyFailed)
XCTAssertEqual(status?.description, "A cryptographic verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecQuerySizeUnknown)
XCTAssertEqual(status, .querySizeUnknown)
XCTAssertEqual(status?.description, "The query size is unknown.")
}
do {
let status = Status(rawValue: errSecBlockSizeMismatch)
XCTAssertEqual(status, .blockSizeMismatch)
XCTAssertEqual(status?.description, "A block size mismatch occurred.")
}
do {
let status = Status(rawValue: errSecPublicKeyInconsistent)
XCTAssertEqual(status, .publicKeyInconsistent)
XCTAssertEqual(status?.description, "The public key was inconsistent.")
}
do {
let status = Status(rawValue: errSecDeviceVerifyFailed)
XCTAssertEqual(status, .deviceVerifyFailed)
XCTAssertEqual(status?.description, "A device verification failure has occurred.")
}
do {
let status = Status(rawValue: errSecInvalidLoginName)
XCTAssertEqual(status, .invalidLoginName)
XCTAssertEqual(status?.description, "An invalid login name was detected.")
}
do {
let status = Status(rawValue: errSecAlreadyLoggedIn)
XCTAssertEqual(status, .alreadyLoggedIn)
XCTAssertEqual(status?.description, "The user is already logged in.")
}
do {
let status = Status(rawValue: errSecInvalidDigestAlgorithm)
XCTAssertEqual(status, .invalidDigestAlgorithm)
XCTAssertEqual(status?.description, "An invalid digest algorithm was detected.")
}
do {
let status = Status(rawValue: errSecInvalidCRLGroup)
XCTAssertEqual(status, .invalidCRLGroup)
XCTAssertEqual(status?.description, "An invalid CRL group was detected.")
}
do {
let status = Status(rawValue: errSecCertificateCannotOperate)
XCTAssertEqual(status, .certificateCannotOperate)
XCTAssertEqual(status?.description, "The certificate cannot operate.")
}
do {
let status = Status(rawValue: errSecCertificateExpired)
XCTAssertEqual(status, .certificateExpired)
XCTAssertEqual(status?.description, "An expired certificate was detected.")
}
do {
let status = Status(rawValue: errSecCertificateNotValidYet)
XCTAssertEqual(status, .certificateNotValidYet)
XCTAssertEqual(status?.description, "The certificate is not yet valid.")
}
do {
let status = Status(rawValue: errSecCertificateRevoked)
XCTAssertEqual(status, .certificateRevoked)
XCTAssertEqual(status?.description, "The certificate was revoked.")
}
do {
let status = Status(rawValue: errSecCertificateSuspended)
XCTAssertEqual(status, .certificateSuspended)
XCTAssertEqual(status?.description, "The certificate was suspended.")
}
do {
let status = Status(rawValue: errSecInsufficientCredentials)
XCTAssertEqual(status, .insufficientCredentials)
XCTAssertEqual(status?.description, "Insufficient credentials were detected.")
}
do {
let status = Status(rawValue: errSecInvalidAction)
XCTAssertEqual(status, .invalidAction)
XCTAssertEqual(status?.description, "The action was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidAuthority)
XCTAssertEqual(status, .invalidAuthority)
XCTAssertEqual(status?.description, "The authority was not valid.")
}
do {
let status = Status(rawValue: errSecVerifyActionFailed)
XCTAssertEqual(status, .verifyActionFailed)
XCTAssertEqual(status?.description, "A verify action has failed.")
}
do {
let status = Status(rawValue: errSecInvalidCertAuthority)
XCTAssertEqual(status, .invalidCertAuthority)
XCTAssertEqual(status?.description, "The certificate authority was not valid.")
}
do {
let status = Status(rawValue: errSecInvaldCRLAuthority)
XCTAssertEqual(status, .invaldCRLAuthority)
XCTAssertEqual(status?.description, "The CRL authority was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRLEncoding)
XCTAssertEqual(status, .invalidCRLEncoding)
XCTAssertEqual(status?.description, "The CRL encoding was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRLType)
XCTAssertEqual(status, .invalidCRLType)
XCTAssertEqual(status?.description, "The CRL type was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRL)
XCTAssertEqual(status, .invalidCRL)
XCTAssertEqual(status?.description, "The CRL was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidFormType)
XCTAssertEqual(status, .invalidFormType)
XCTAssertEqual(status?.description, "The form type was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidID)
XCTAssertEqual(status, .invalidID)
XCTAssertEqual(status?.description, "The ID was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIdentifier)
XCTAssertEqual(status, .invalidIdentifier)
XCTAssertEqual(status?.description, "The identifier was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIndex)
XCTAssertEqual(status, .invalidIndex)
XCTAssertEqual(status?.description, "The index was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidPolicyIdentifiers)
XCTAssertEqual(status, .invalidPolicyIdentifiers)
XCTAssertEqual(status?.description, "The policy identifiers are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidTimeString)
XCTAssertEqual(status, .invalidTimeString)
XCTAssertEqual(status?.description, "The time specified was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidReason)
XCTAssertEqual(status, .invalidReason)
XCTAssertEqual(status?.description, "The trust policy reason was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidRequestInputs)
XCTAssertEqual(status, .invalidRequestInputs)
XCTAssertEqual(status?.description, "The request inputs are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidResponseVector)
XCTAssertEqual(status, .invalidResponseVector)
XCTAssertEqual(status?.description, "The response vector was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidStopOnPolicy)
XCTAssertEqual(status, .invalidStopOnPolicy)
XCTAssertEqual(status?.description, "The stop-on policy was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidTuple)
XCTAssertEqual(status, .invalidTuple)
XCTAssertEqual(status?.description, "The tuple was not valid.")
}
do {
let status = Status(rawValue: errSecMultipleValuesUnsupported)
XCTAssertEqual(status, .multipleValuesUnsupported)
XCTAssertEqual(status?.description, "Multiple values are not supported.")
}
do {
let status = Status(rawValue: errSecNotTrusted)
XCTAssertEqual(status, .notTrusted)
XCTAssertEqual(status?.description, "The trust policy was not trusted.")
}
do {
let status = Status(rawValue: errSecNoDefaultAuthority)
XCTAssertEqual(status, .noDefaultAuthority)
XCTAssertEqual(status?.description, "No default authority was detected.")
}
do {
let status = Status(rawValue: errSecRejectedForm)
XCTAssertEqual(status, .rejectedForm)
XCTAssertEqual(status?.description, "The trust policy had a rejected form.")
}
do {
let status = Status(rawValue: errSecRequestLost)
XCTAssertEqual(status, .requestLost)
XCTAssertEqual(status?.description, "The request was lost.")
}
do {
let status = Status(rawValue: errSecRequestRejected)
XCTAssertEqual(status, .requestRejected)
XCTAssertEqual(status?.description, "The request was rejected.")
}
do {
let status = Status(rawValue: errSecUnsupportedAddressType)
XCTAssertEqual(status, .unsupportedAddressType)
XCTAssertEqual(status?.description, "The address type is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedService)
XCTAssertEqual(status, .unsupportedService)
XCTAssertEqual(status?.description, "The service is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidTupleGroup)
XCTAssertEqual(status, .invalidTupleGroup)
XCTAssertEqual(status?.description, "The tuple group was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidBaseACLs)
XCTAssertEqual(status, .invalidBaseACLs)
XCTAssertEqual(status?.description, "The base ACLs are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidTupleCredendtials)
XCTAssertEqual(status, .invalidTupleCredendtials)
XCTAssertEqual(status?.description, "The tuple credentials are not valid.")
}
do {
let status = Status(rawValue: errSecInvalidEncoding)
XCTAssertEqual(status, .invalidEncoding)
XCTAssertEqual(status?.description, "The encoding was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidValidityPeriod)
XCTAssertEqual(status, .invalidValidityPeriod)
XCTAssertEqual(status?.description, "The validity period was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidRequestor)
XCTAssertEqual(status, .invalidRequestor)
XCTAssertEqual(status?.description, "The requestor was not valid.")
}
do {
let status = Status(rawValue: errSecRequestDescriptor)
XCTAssertEqual(status, .requestDescriptor)
XCTAssertEqual(status?.description, "The request descriptor was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidBundleInfo)
XCTAssertEqual(status, .invalidBundleInfo)
XCTAssertEqual(status?.description, "The bundle information was not valid.")
}
do {
let status = Status(rawValue: errSecInvalidCRLIndex)
XCTAssertEqual(status, .invalidCRLIndex)
XCTAssertEqual(status?.description, "The CRL index was not valid.")
}
do {
let status = Status(rawValue: errSecNoFieldValues)
XCTAssertEqual(status, .noFieldValues)
XCTAssertEqual(status?.description, "No field values were detected.")
}
do {
let status = Status(rawValue: errSecUnsupportedFieldFormat)
XCTAssertEqual(status, .unsupportedFieldFormat)
XCTAssertEqual(status?.description, "The field format is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedIndexInfo)
XCTAssertEqual(status, .unsupportedIndexInfo)
XCTAssertEqual(status?.description, "The index information is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedLocality)
XCTAssertEqual(status, .unsupportedLocality)
XCTAssertEqual(status?.description, "The locality is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumAttributes)
XCTAssertEqual(status, .unsupportedNumAttributes)
XCTAssertEqual(status?.description, "The number of attributes is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumIndexes)
XCTAssertEqual(status, .unsupportedNumIndexes)
XCTAssertEqual(status?.description, "The number of indexes is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumRecordTypes)
XCTAssertEqual(status, .unsupportedNumRecordTypes)
XCTAssertEqual(status?.description, "The number of record types is not supported.")
}
do {
let status = Status(rawValue: errSecFieldSpecifiedMultiple)
XCTAssertEqual(status, .fieldSpecifiedMultiple)
XCTAssertEqual(status?.description, "Too many fields were specified.")
}
do {
let status = Status(rawValue: errSecIncompatibleFieldFormat)
XCTAssertEqual(status, .incompatibleFieldFormat)
XCTAssertEqual(status?.description, "The field format was incompatible.")
}
do {
let status = Status(rawValue: errSecInvalidParsingModule)
XCTAssertEqual(status, .invalidParsingModule)
XCTAssertEqual(status?.description, "The parsing module was not valid.")
}
do {
let status = Status(rawValue: errSecDatabaseLocked)
XCTAssertEqual(status, .databaseLocked)
XCTAssertEqual(status?.description, "The database is locked.")
}
do {
let status = Status(rawValue: errSecDatastoreIsOpen)
XCTAssertEqual(status, .datastoreIsOpen)
XCTAssertEqual(status?.description, "The data store is open.")
}
do {
let status = Status(rawValue: errSecMissingValue)
XCTAssertEqual(status, .missingValue)
XCTAssertEqual(status?.description, "A missing value was detected.")
}
do {
let status = Status(rawValue: errSecUnsupportedQueryLimits)
XCTAssertEqual(status, .unsupportedQueryLimits)
XCTAssertEqual(status?.description, "The query limits are not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedNumSelectionPreds)
XCTAssertEqual(status, .unsupportedNumSelectionPreds)
XCTAssertEqual(status?.description, "The number of selection predicates is not supported.")
}
do {
let status = Status(rawValue: errSecUnsupportedOperator)
XCTAssertEqual(status, .unsupportedOperator)
XCTAssertEqual(status?.description, "The operator is not supported.")
}
do {
let status = Status(rawValue: errSecInvalidDBLocation)
XCTAssertEqual(status, .invalidDBLocation)
XCTAssertEqual(status?.description, "The database location is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidAccessRequest)
XCTAssertEqual(status, .invalidAccessRequest)
XCTAssertEqual(status?.description, "The access request is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidIndexInfo)
XCTAssertEqual(status, .invalidIndexInfo)
XCTAssertEqual(status?.description, "The index information is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidNewOwner)
XCTAssertEqual(status, .invalidNewOwner)
XCTAssertEqual(status?.description, "The new owner is not valid.")
}
do {
let status = Status(rawValue: errSecInvalidModifyMode)
XCTAssertEqual(status, .invalidModifyMode)
XCTAssertEqual(status?.description, "The modify mode is not valid.")
}
do {
let status = Status(rawValue: errSecMissingRequiredExtension)
XCTAssertEqual(status, .missingRequiredExtension)
XCTAssertEqual(status?.description, "A required certificate extension is missing.")
}
do {
let status = Status(rawValue: errSecExtendedKeyUsageNotCritical)
XCTAssertEqual(status, .extendedKeyUsageNotCritical)
XCTAssertEqual(status?.description, "The extended key usage extension was not marked critical.")
}
do {
let status = Status(rawValue: errSecTimestampMissing)
XCTAssertEqual(status, .timestampMissing)
XCTAssertEqual(status?.description, "A timestamp was expected but was not found.")
}
do {
let status = Status(rawValue: errSecTimestampInvalid)
XCTAssertEqual(status, .timestampInvalid)
XCTAssertEqual(status?.description, "The timestamp was not valid.")
}
do {
let status = Status(rawValue: errSecTimestampNotTrusted)
XCTAssertEqual(status, .timestampNotTrusted)
XCTAssertEqual(status?.description, "The timestamp was not trusted.")
}
do {
let status = Status(rawValue: errSecTimestampServiceNotAvailable)
XCTAssertEqual(status, .timestampServiceNotAvailable)
XCTAssertEqual(status?.description, "The timestamp service is not available.")
}
do {
let status = Status(rawValue: errSecTimestampBadAlg)
XCTAssertEqual(status, .timestampBadAlg)
XCTAssertEqual(status?.description, "An unrecognized or unsupported Algorithm Identifier in timestamp.")
}
do {
let status = Status(rawValue: errSecTimestampBadRequest)
XCTAssertEqual(status, .timestampBadRequest)
XCTAssertEqual(status?.description, "The timestamp transaction is not permitted or supported.")
}
do {
let status = Status(rawValue: errSecTimestampBadDataFormat)
XCTAssertEqual(status, .timestampBadDataFormat)
XCTAssertEqual(status?.description, "The timestamp data submitted has the wrong format.")
}
do {
let status = Status(rawValue: errSecTimestampTimeNotAvailable)
XCTAssertEqual(status, .timestampTimeNotAvailable)
XCTAssertEqual(status?.description, "The time source for the Timestamp Authority is not available.")
}
do {
let status = Status(rawValue: errSecTimestampUnacceptedPolicy)
XCTAssertEqual(status, .timestampUnacceptedPolicy)
XCTAssertEqual(status?.description, "The requested policy is not supported by the Timestamp Authority.")
}
do {
let status = Status(rawValue: errSecTimestampUnacceptedExtension)
XCTAssertEqual(status, .timestampUnacceptedExtension)
XCTAssertEqual(status?.description, "The requested extension is not supported by the Timestamp Authority.")
}
do {
let status = Status(rawValue: errSecTimestampAddInfoNotAvailable)
XCTAssertEqual(status, .timestampAddInfoNotAvailable)
XCTAssertEqual(status?.description, "The additional information requested is not available.")
}
do {
let status = Status(rawValue: errSecTimestampSystemFailure)
XCTAssertEqual(status, .timestampSystemFailure)
XCTAssertEqual(status?.description, "The timestamp request cannot be handled due to system failure.")
}
do {
let status = Status(rawValue: errSecSigningTimeMissing)
XCTAssertEqual(status, .signingTimeMissing)
XCTAssertEqual(status?.description, "A signing time was expected but was not found.")
}
do {
let status = Status(rawValue: errSecTimestampRejection)
XCTAssertEqual(status, .timestampRejection)
XCTAssertEqual(status?.description, "A timestamp transaction was rejected.")
}
do {
let status = Status(rawValue: errSecTimestampWaiting)
XCTAssertEqual(status, .timestampWaiting)
XCTAssertEqual(status?.description, "A timestamp transaction is waiting.")
}
do {
let status = Status(rawValue: errSecTimestampRevocationWarning)
XCTAssertEqual(status, .timestampRevocationWarning)
XCTAssertEqual(status?.description, "A timestamp authority revocation warning was issued.")
}
do {
let status = Status(rawValue: errSecTimestampRevocationNotification)
XCTAssertEqual(status, .timestampRevocationNotification)
XCTAssertEqual(status?.description, "A timestamp authority revocation notification was issued.")
}
#endif
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
1
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/KeychainAccessTests.swift
================================================
//
// KeychainAccessTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 2014/12/24.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import XCTest
import KeychainAccess
class KeychainAccessTests: XCTestCase {
override func setUp() {
super.setUp()
do { try Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").removeAll() } catch {}
do { try Keychain(service: "Twitter").removeAll() } catch {}
do { try Keychain(server: URL(string: "https://example.com")!, protocolType: .https).removeAll() } catch {}
do { try Keychain(server: URL(string: "https://example.com:443")!, protocolType: .https).removeAll() } catch {}
do { try Keychain().removeAll() } catch {}
}
override func tearDown() {
super.tearDown()
}
// MARK:
func testGenericPassword() {
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter")
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "kishikawa_katsumi")
let password = try! keychain.get("password")
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter")
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "katsumi_kishikawa")
let password = try! keychain.get("password")
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter")
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testGenericPasswordSubscripting() {
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
keychain["username"] = "kishikawa_katsumi"
keychain["password"] = "password_1234"
let username = keychain["username"]
XCTAssertEqual(username, "kishikawa_katsumi")
let password = keychain["password"]
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
keychain["username"] = "katsumi_kishikawa"
keychain["password"] = "1234_password"
let username = keychain["username"]
XCTAssertEqual(username, "katsumi_kishikawa")
let password = keychain["password"]
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
keychain["username"] = nil
keychain["password"] = nil
XCTAssertNil(keychain["username"])
XCTAssertNil(keychain["password"])
}
}
func testGenericPasswordWithAccessGroup1() {
do {
// Add Keychain items
// This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
// kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
// https://developer.apple.com/documentation/security/ksecattraccessgroup
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychainWithAccessGroup.remove("username") } catch {}
do { try keychainWithAccessGroup.remove("password") } catch {}
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
XCTAssertNotNil(try! keychain.get("username"))
XCTAssertNotNil(try! keychain.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testGenericPasswordWithAccessGroup2() {
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter").synchronizable(true)
let keychainWithAccessGroup = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
// If the access group is empty, the query will match all access group. So delete all values in other access groups.
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
}
}
// MARK:
func testInternetPassword() {
do {
// Add Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "kishikawa_katsumi")
let password = try! keychain.get("password")
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
let username = try! keychain.get("username")
XCTAssertEqual(username, "katsumi_kishikawa")
let password = try! keychain.get("password")
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testInternetPasswordSubscripting() {
do {
// Add Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
keychain["username"] = "kishikawa_katsumi"
keychain["password"] = "password_1234"
let username = keychain["username"]
XCTAssertEqual(username, "kishikawa_katsumi")
let password = keychain["password"]
XCTAssertEqual(password, "password_1234")
}
do {
// Update Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
keychain["username"] = "katsumi_kishikawa"
keychain["password"] = "1234_password"
let username = keychain["username"]
XCTAssertEqual(username, "katsumi_kishikawa")
let password = keychain["password"]
XCTAssertEqual(password, "1234_password")
}
do {
// Remove Keychain items
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
keychain["username"] = nil
keychain["password"] = nil
XCTAssertNil(keychain["username"])
XCTAssertNil(keychain["password"])
}
}
func testInternetPasswordWithAccessGroup1() {
do {
// Add Keychain items
// This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
// kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
// https://developer.apple.com/documentation/security/ksecattraccessgroup
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychainWithAccessGroup.remove("username") } catch {}
do { try keychainWithAccessGroup.remove("password") } catch {}
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
XCTAssertNotNil(try! keychain.get("username"))
XCTAssertNotNil(try! keychain.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
}
}
func testInternetPasswordWithAccessGroup2() {
do {
// Add Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
do { try keychain.set("password_1234", key: "password") } catch {}
do { try keychainWithAccessGroup.set("kishikawa_katsumi_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("password_1234_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawa_katsumi")
XCTAssertEqual(try! keychain.get("password"), "password_1234")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "kishikawa_katsumi_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "password_1234_access_group")
}
do {
// Update Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
do { try keychain.set("1234_password", key: "password") } catch {}
do { try keychainWithAccessGroup.set("katsumi_kishikawa_access_group", key: "username") } catch {}
do { try keychainWithAccessGroup.set("1234_password_access_group", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "katsumi_kishikawa")
XCTAssertEqual(try! keychain.get("password"), "1234_password")
XCTAssertEqual(try! keychainWithAccessGroup.get("username"), "katsumi_kishikawa_access_group")
XCTAssertEqual(try! keychainWithAccessGroup.get("password"), "1234_password_access_group")
}
do {
// Remove Keychain items
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https).synchronizable(true)
let keychainWithAccessGroup = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https, accessGroup: "27AEDK3C9F.shared").synchronizable(true)
XCTAssertNotNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNotNil(try! keychainWithAccessGroup.get("password"))
do { try keychain.remove("username") } catch {}
do { try keychain.remove("password") } catch {}
// If the access group is empty, the query will match all access group. So delete all values in other access groups.
XCTAssertNil(try! keychain.get("username"))
XCTAssertNil(try! keychain.get("password"))
XCTAssertNil(try! keychainWithAccessGroup.get("username"))
XCTAssertNil(try! keychainWithAccessGroup.get("password"))
}
}
// MARK:
func testDefaultInitializer() {
let keychain = Keychain()
XCTAssertEqual(keychain.service, Bundle.main.bundleIdentifier)
let service: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(keychain.service, service)
XCTAssertNil(keychain.accessGroup)
}
func testInitializerWithService() {
let keychain = Keychain(service: "com.example.github-token")
XCTAssertEqual(keychain.service, "com.example.github-token")
XCTAssertNil(keychain.accessGroup)
}
func testInitializerWithAccessGroup() {
let keychain = Keychain(accessGroup: "27AEDK3C9F.shared")
let service: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(keychain.service, service)
XCTAssertEqual(keychain.accessGroup, "27AEDK3C9F.shared")
}
func testInitializerWithServiceAndAccessGroup() {
let keychain = Keychain(service: "com.example.github-token", accessGroup: "27AEDK3C9F.shared")
XCTAssertEqual(keychain.service, "com.example.github-token")
XCTAssertEqual(keychain.accessGroup, "27AEDK3C9F.shared")
}
func testInitializerWithServer() {
let server = "https://kishikawakatsumi.com"
let url = URL(string: server)!
do {
let keychain = Keychain(server: server, protocolType: .https)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.default)
}
do {
let keychain = Keychain(server: url, protocolType: .https)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.default)
}
}
func testInitializerWithServerAndAuthenticationType() {
let server = "https://kishikawakatsumi.com"
let url = URL(string: server)!
do {
let keychain = Keychain(server: server, protocolType: .https, authenticationType: .htmlForm)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.htmlForm)
}
do {
let keychain = Keychain(server: url, protocolType: .https, authenticationType: .htmlForm)
XCTAssertEqual(keychain.server, url)
XCTAssertEqual(keychain.protocolType, ProtocolType.https)
XCTAssertEqual(keychain.authenticationType, AuthenticationType.htmlForm)
}
}
// MARK:
func testContains() {
let keychain = Keychain(service: "Twitter")
XCTAssertFalse(try! keychain.contains("username"), "not stored username")
XCTAssertFalse(try! keychain.contains("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertTrue(try! keychain.contains("username"), "stored username")
XCTAssertFalse(try! keychain.contains("password"), "not stored password")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertTrue(try! keychain.contains("username"), "stored username")
XCTAssertTrue(try! keychain.contains("password"), "stored password")
}
// MARK:
func testSetString() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
}
func testSetStringWithLabel() {
let keychain = Keychain(service: "Twitter")
.label("Twitter Account")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertNil(label)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertEqual(label, "Twitter Account")
} catch {
XCTFail("error occurred")
}
}
func testSetStringWithComment() {
let keychain = Keychain(service: "Twitter")
.comment("Kishikawa Katsumi")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertNil(comment)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertEqual(comment, "Kishikawa Katsumi")
} catch {
XCTFail("error occurred")
}
}
func testSetStringWithLabelAndComment() {
let keychain = Keychain(service: "Twitter")
.label("Twitter Account")
.comment("Kishikawa Katsumi")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertNil(label)
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertNil(comment)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.label
}
XCTAssertEqual(label, "Twitter Account")
let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
return attributes?.comment
}
XCTAssertEqual(comment, "Kishikawa Katsumi")
} catch {
XCTFail("error occurred")
}
}
func testSetData() {
let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
let JSONData = try! JSONSerialization.data(withJSONObject: JSONObject, options: [])
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
do { try keychain.set(JSONData, key: "JSONData") } catch {}
XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
}
func testStringConversionError() {
let keychain = Keychain(service: "Twitter")
let length = 256
let data = NSMutableData(length: length)!
let bytes = data.mutableBytes.bindMemory(to: UInt8.self, capacity: length)
_ = SecRandomCopyBytes(kSecRandomDefault, length, bytes)
do {
try keychain.set(data as Data, key: "RandomData")
let _ = try keychain.getString("RandomData")
XCTFail("no error occurred")
} catch let error as NSError {
XCTAssertEqual(error.domain, KeychainAccessErrorDomain)
XCTAssertEqual(error.code, Int(Status.conversionError.rawValue))
XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as! String, Status.conversionError.localizedDescription)
} catch {
XCTFail("unexpected error occurred")
}
do {
try keychain.set(data as Data, key: "RandomData")
let _ = try keychain.getString("RandomData")
XCTFail("no error occurred")
} catch Status.conversionError {
XCTAssertTrue(true)
} catch {
XCTFail("unexpected error occurred")
}
}
func testGetPersistentRef() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
XCTAssertNil(persistentRef)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
XCTAssertNotNil(persistentRef)
} catch {
XCTFail("error occurred")
}
}
#if os(iOS) || os(tvOS)
func testSetAttributes() {
do {
var attributes = [String: Any]()
attributes[String(kSecAttrDescription)] = "Description Test"
attributes[String(kSecAttrComment)] = "Comment Test"
attributes[String(kSecAttrCreator)] = "Creator Test"
attributes[String(kSecAttrType)] = "Type Test"
attributes[String(kSecAttrLabel)] = "Label Test"
attributes[String(kSecAttrIsInvisible)] = true
attributes[String(kSecAttrIsNegative)] = true
let keychain = Keychain(service: "Twitter")
.attributes(attributes)
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertNil(attributes)
} catch {
XCTFail("error occurred")
}
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertEqual(attributes?.`class`, ItemClass.genericPassword.rawValue)
XCTAssertEqual(attributes?.data, "password1234".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if targetEnvironment(macCatalyst)
XCTAssertNotNil(attributes?.accessControl)
#else
if ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 11, minorVersion: 3, patchVersion: 0)) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Description Test")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertEqual(attributes?.service, "Twitter")
XCTAssertNil(attributes?.generic)
XCTAssertNil(attributes?.securityDomain)
XCTAssertNil(attributes?.server)
XCTAssertNil(attributes?.`protocol`)
XCTAssertNil(attributes?.authenticationType)
XCTAssertNil(attributes?.port)
XCTAssertNil(attributes?.path)
XCTAssertEqual(attributes?[String(kSecClass)] as? String, ItemClass.genericPassword.rawValue)
XCTAssertEqual(attributes?[String(kSecValueData)] as? Data, "password1234".data(using: .utf8))
} catch {
XCTFail("error occurred")
}
}
do {
var attributes = [String: Any]()
attributes[String(kSecAttrDescription)] = "Description Test"
attributes[String(kSecAttrComment)] = "Comment Test"
attributes[String(kSecAttrCreator)] = "Creator Test"
attributes[String(kSecAttrType)] = "Type Test"
attributes[String(kSecAttrLabel)] = "Label Test"
attributes[String(kSecAttrIsInvisible)] = true
attributes[String(kSecAttrIsNegative)] = true
attributes[String(kSecAttrSecurityDomain)] = "securitydomain"
let keychain = Keychain(server: URL(string: "https://example.com:443/api/login/")!, protocolType: .https)
.attributes(attributes)
XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertNil(attributes)
} catch {
XCTFail("error occurred")
}
do {
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertEqual(attributes?.`class`, ItemClass.internetPassword.rawValue)
XCTAssertEqual(attributes?.data, "password1234".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if os(iOS)
if #available(iOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else if #available(iOS 9.0, *) {
XCTAssertNil(attributes?.accessControl)
} else {
XCTAssertNotNil(attributes?.accessControl)
}
#else
if #available(tvOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Description Test")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertNil(attributes?.service)
XCTAssertNil(attributes?.generic)
XCTAssertEqual(attributes?.securityDomain, "securitydomain")
XCTAssertEqual(attributes?.server, "example.com")
XCTAssertEqual(attributes?.`protocol`, ProtocolType.https.rawValue)
XCTAssertEqual(attributes?.authenticationType, AuthenticationType.default.rawValue)
XCTAssertEqual(attributes?.port, 443)
XCTAssertEqual(attributes?.path, "")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(server: URL(string: "https://example.com:443/api/login/")!, protocolType: .https)
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
keychain["kishikawakatsumi"] = "1234password"
XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "updated password")
let attributes = try keychain.get("kishikawakatsumi") { $0 }
XCTAssertEqual(attributes?.`class`, ItemClass.internetPassword.rawValue)
XCTAssertEqual(attributes?.data, "1234password".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if os(iOS)
if #available(iOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else if #available(iOS 9.0, *) {
XCTAssertNil(attributes?.accessControl)
} else {
XCTAssertNotNil(attributes?.accessControl)
}
#else
if #available(tvOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Description Test")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertNil(attributes?.service)
XCTAssertNil(attributes?.generic)
XCTAssertEqual(attributes?.securityDomain, "securitydomain")
XCTAssertEqual(attributes?.server, "example.com")
XCTAssertEqual(attributes?.`protocol`, ProtocolType.https.rawValue)
XCTAssertEqual(attributes?.authenticationType, AuthenticationType.default.rawValue)
XCTAssertEqual(attributes?.port, 443)
XCTAssertEqual(attributes?.path, "")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(server: URL(string: "https://example.com:443/api/login/")!, protocolType: .https)
.attributes([String(kSecAttrDescription): "Updated Description"])
XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "stored password")
keychain["kishikawakatsumi"] = "password1234"
XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "updated password")
let attributes = keychain[attributes: "kishikawakatsumi"]
XCTAssertEqual(attributes?.`class`, ItemClass.internetPassword.rawValue)
XCTAssertEqual(attributes?.data, "password1234".data(using: .utf8))
XCTAssertNil(attributes?.ref)
XCTAssertNotNil(attributes?.persistentRef)
XCTAssertEqual(attributes?.accessible, Accessibility.afterFirstUnlock.rawValue)
#if os(iOS)
if #available(iOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else if #available(iOS 9.0, *) {
XCTAssertNil(attributes?.accessControl)
} else {
XCTAssertNotNil(attributes?.accessControl)
}
#else
if #available(tvOS 11.3, *) {
XCTAssertNotNil(attributes?.accessControl)
} else {
XCTAssertNil(attributes?.accessControl)
}
#endif
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(attributes?.accessGroup, accessGroup)
XCTAssertNotNil(attributes?.synchronizable)
XCTAssertNotNil(attributes?.creationDate)
XCTAssertNotNil(attributes?.modificationDate)
XCTAssertEqual(attributes?.attributeDescription, "Updated Description")
XCTAssertEqual(attributes?.comment, "Comment Test")
XCTAssertEqual(attributes?.creator, "Creator Test")
XCTAssertEqual(attributes?.type, "Type Test")
XCTAssertEqual(attributes?.label, "Label Test")
XCTAssertEqual(attributes?.isInvisible, true)
XCTAssertEqual(attributes?.isNegative, true)
XCTAssertEqual(attributes?.account, "kishikawakatsumi")
XCTAssertNil(attributes?.service)
XCTAssertNil(attributes?.generic)
XCTAssertEqual(attributes?.securityDomain, "securitydomain")
XCTAssertEqual(attributes?.server, "example.com")
XCTAssertEqual(attributes?.`protocol`, ProtocolType.https.rawValue)
XCTAssertEqual(attributes?.authenticationType, AuthenticationType.default.rawValue)
XCTAssertEqual(attributes?.port, 443)
XCTAssertEqual(attributes?.path, "")
}
}
}
#endif
func testRemoveString() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
do { try keychain.remove("username") } catch {}
XCTAssertNil(try! keychain.get("username"), "removed username")
XCTAssertEqual(try! keychain.get("password"), "password1234", "left password")
do { try keychain.remove("password") } catch {}
XCTAssertNil(try! keychain.get("username"), "removed username")
XCTAssertNil(try! keychain.get("password"), "removed password")
}
func testRemoveData() {
let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
let JSONData = try! JSONSerialization.data(withJSONObject: JSONObject, options: [])
let keychain = Keychain(service: "Twitter")
XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
do { try keychain.set(JSONData, key: "JSONData") } catch {}
XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
do { try keychain.remove("JSONData") } catch {}
XCTAssertNil(try! keychain.getData("JSONData"), "removed JSON data")
}
// MARK:
func testSubscripting() {
let keychain = Keychain(service: "Twitter")
XCTAssertNil(keychain["username"], "not stored username")
XCTAssertNil(keychain["password"], "not stored password")
XCTAssertNil(keychain[string: "username"], "not stored username")
XCTAssertNil(keychain[string: "password"], "not stored password")
keychain["username"] = "kishikawakatsumi"
XCTAssertEqual(keychain["username"], "kishikawakatsumi", "stored username")
XCTAssertEqual(keychain[string: "username"], "kishikawakatsumi", "stored username")
keychain["password"] = "password1234"
XCTAssertEqual(keychain["password"], "password1234", "stored password")
XCTAssertEqual(keychain[string: "password"], "password1234", "stored password")
keychain[string: "username"] = nil
XCTAssertNil(keychain["username"], "removed username")
XCTAssertEqual(keychain["password"], "password1234", "left password")
XCTAssertNil(keychain[string: "username"], "removed username")
XCTAssertEqual(keychain[string: "password"], "password1234", "left password")
keychain[string: "password"] = nil
XCTAssertNil(keychain["username"], "removed username")
XCTAssertNil(keychain["password"], "removed password")
XCTAssertNil(keychain[string: "username"], "removed username")
XCTAssertNil(keychain[string: "password"], "removed password")
let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
let JSONData = try! JSONSerialization.data(withJSONObject: JSONObject, options: [])
XCTAssertNil(keychain[data:"JSONData"], "not stored JSON data")
keychain[data: "JSONData"] = JSONData
XCTAssertEqual(keychain[data: "JSONData"], JSONData, "stored JSON data")
keychain[data: "JSONData"] = nil
XCTAssertNil(keychain[data:"JSONData"], "removed JSON data")
}
// MARK:
func testErrorHandling() {
do {
let keychain = Keychain(service: "Twitter", accessGroup: "27AEDK3C9F.shared")
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(service: "Twitter")
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain(server: URL(string: "https://kishikawakatsumi.com")!, protocolType: .https)
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let keychain = Keychain()
try keychain.removeAll()
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
// Add Keychain items
let keychain = Keychain(service: "Twitter")
do {
try keychain.set("kishikawa_katsumi", key: "username")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
try keychain.set("password_1234", key: "password")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let username = try keychain.get("username")
XCTAssertEqual(username, "kishikawa_katsumi")
} catch {
XCTFail("error occurred")
}
do {
let password = try keychain.get("password")
XCTAssertEqual(password, "password_1234")
} catch {
XCTFail("error occurred")
}
}
do {
// Update Keychain items
let keychain = Keychain(service: "Twitter")
do {
try keychain.set("katsumi_kishikawa", key: "username")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
try keychain.set("1234_password", key: "password")
XCTAssertTrue(true, "no error occurred")
} catch {
XCTFail("error occurred")
}
do {
let username = try keychain.get("username")
XCTAssertEqual(username, "katsumi_kishikawa")
} catch {
XCTFail("error occurred")
}
do {
let password = try keychain.get("password")
XCTAssertEqual(password, "1234_password")
} catch {
XCTFail("error occurred")
}
}
do {
// Remove Keychain items
let keychain = Keychain(service: "Twitter")
do {
try keychain.remove("username")
XCTAssertNil(try! keychain.get("username"))
} catch {
XCTFail("error occurred")
}
do {
try keychain.remove("password")
XCTAssertNil(try! keychain.get("username"))
} catch {
XCTFail("error occurred")
}
}
}
// MARK:
func testSetStringWithCustomService() {
let username_1 = "kishikawakatsumi"
let password_1 = "password1234"
let username_2 = "kishikawa_katsumi"
let password_2 = "password_1234"
let username_3 = "k_katsumi"
let password_3 = "12341234"
let service_1 = ""
let service_2 = "com.kishikawakatsumi.KeychainAccess"
let service_3 = "example.com"
do { try Keychain().removeAll() } catch {}
do { try Keychain(service: service_1).removeAll() } catch {}
do { try Keychain(service: service_2).removeAll() } catch {}
do { try Keychain(service: service_3).removeAll() } catch {}
XCTAssertNil(try! Keychain().get("username"), "not stored username")
XCTAssertNil(try! Keychain().get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain().set(username_1, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
do { try Keychain(service: service_1).set(username_1, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
do { try Keychain(service: service_2).set(username_2, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
do { try Keychain(service: service_3).set(username_3, key: "username") } catch {}
XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "stored username")
do { try Keychain().set(password_1, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain(service: service_1).set(password_1, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain(service: service_2).set(password_2, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
do { try Keychain(service: service_3).set(password_3, key: "password") } catch {}
XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "stored password")
do { try Keychain().remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "left username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
do { try Keychain(service: service_1).remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
do { try Keychain(service: service_2).remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
do { try Keychain(service: service_3).remove("username") } catch {}
XCTAssertNil(try! Keychain().get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
XCTAssertNil(try! Keychain(service: service_3).get("username"), "removed username")
do { try Keychain().remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "left password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
do { try Keychain(service: service_1).remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
do { try Keychain(service: service_2).remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
do { try Keychain(service: service_3).remove("password") } catch {}
XCTAssertNil(try! Keychain().get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
}
// MARK:
func testProperties() {
guard #available(OSX 10.10, *) else {
return
}
let keychain = Keychain()
XCTAssertEqual(keychain.synchronizable, false)
XCTAssertEqual(keychain.synchronizable(true).synchronizable, true)
XCTAssertEqual(keychain.synchronizable(false).synchronizable, false)
XCTAssertEqual(keychain.accessibility(.afterFirstUnlock).accessibility, Accessibility.afterFirstUnlock)
XCTAssertEqual(keychain.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence).accessibility, Accessibility.whenPasscodeSetThisDeviceOnly)
XCTAssertEqual(keychain.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence).authenticationPolicy, AuthenticationPolicy.userPresence)
XCTAssertNil(keychain.label)
XCTAssertEqual(keychain.label("Label").label, "Label")
XCTAssertNil(keychain.comment)
XCTAssertEqual(keychain.comment("Comment").comment, "Comment")
XCTAssertEqual(keychain.authenticationPrompt("Prompt").authenticationPrompt, "Prompt")
}
// MARK:
func testAllKeys() {
do {
let keychain = Keychain()
keychain["key1"] = "value1"
keychain["key2"] = "value2"
keychain["key3"] = "value3"
let allKeys = keychain.allKeys()
XCTAssertEqual(allKeys.count, 3)
XCTAssertEqual(allKeys.sorted(), ["key1", "key2", "key3"])
let allItems = keychain.allItems()
XCTAssertEqual(allItems.count, 3)
let sortedItems = allItems.sorted { (item1, item2) -> Bool in
let key1 = item1["key"] as! String
let key2 = item2["key"] as! String
return key1.compare(key2) == .orderedAscending || key1.compare(key2) == .orderedSame
}
#if !os(OSX)
let service: String
let accessGroup: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[0]["service"] as? String, service)
XCTAssertEqual(sortedItems[0]["value"] as? String, "value1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AfterFirstUnlock")
XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[1]["service"] as? String, service)
XCTAssertEqual(sortedItems[1]["value"] as? String, "value2")
XCTAssertEqual(sortedItems[1]["key"] as? String, "key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlock")
XCTAssertEqual(sortedItems[2]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[2]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[2]["service"] as? String, service)
XCTAssertEqual(sortedItems[2]["value"] as? String, "value3")
XCTAssertEqual(sortedItems[2]["key"] as? String, "key3")
XCTAssertEqual(sortedItems[2]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[2]["accessibility"] as? String, "AfterFirstUnlock")
#else
XCTAssertEqual(sortedItems[0]["service"] as? String, "com.kishikawakatsumi.KeychainAccess.TestHost")
XCTAssertEqual(sortedItems[0]["key"] as? String, "key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["service"] as? String, "com.kishikawakatsumi.KeychainAccess.TestHost")
XCTAssertEqual(sortedItems[1]["key"] as? String, "key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[2]["service"] as? String, "com.kishikawakatsumi.KeychainAccess.TestHost")
XCTAssertEqual(sortedItems[2]["key"] as? String, "key3")
XCTAssertEqual(sortedItems[2]["class"] as? String, "GenericPassword")
#endif
}
do {
let keychain = Keychain(service: "service1")
try! keychain
.synchronizable(true)
.accessibility(.whenUnlockedThisDeviceOnly)
.set("service1_value1", key: "service1_key1")
try! keychain
.synchronizable(false)
.accessibility(.afterFirstUnlockThisDeviceOnly)
.set("service1_value2", key: "service1_key2")
let allKeys = keychain.allKeys()
XCTAssertEqual(allKeys.count, 2)
XCTAssertEqual(allKeys.sorted(), ["service1_key1", "service1_key2"])
let allItems = keychain.allItems()
XCTAssertEqual(allItems.count, 2)
let sortedItems = allItems.sorted { (item1, item2) -> Bool in
let key1 = item1["key"] as! String
let key2 = item2["key"] as! String
return key1.compare(key2) == .orderedAscending || key1.compare(key2) == .orderedSame
}
#if !os(OSX)
let accessGroup: String
#if targetEnvironment(macCatalyst)
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
accessGroup = "27AEDK3C9F.com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "true")
XCTAssertEqual(sortedItems[0]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[0]["value"] as? String, "service1_value1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "service1_key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "WhenUnlockedThisDeviceOnly")
XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, accessGroup)
XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[1]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[1]["value"] as? String, "service1_value2")
XCTAssertEqual(sortedItems[1]["key"] as? String, "service1_key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlockThisDeviceOnly")
#else
XCTAssertEqual(sortedItems[0]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "service1_key1")
XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
XCTAssertEqual(sortedItems[1]["service"] as? String, "service1")
XCTAssertEqual(sortedItems[1]["key"] as? String, "service1_key2")
XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
#endif
}
do {
let keychain = Keychain(server: "https://google.com", protocolType: .https)
#if !targetEnvironment(macCatalyst)
try! keychain
.synchronizable(false)
.accessibility(.alwaysThisDeviceOnly)
.set("google.com_value1", key: "google.com_key1")
#else
try! keychain
.synchronizable(false)
.accessibility(.afterFirstUnlockThisDeviceOnly)
.set("google.com_value1", key: "google.com_key1")
#endif
#if !targetEnvironment(macCatalyst)
try! keychain
.synchronizable(true)
.accessibility(.always)
.set("google.com_value2", key: "google.com_key2")
#else
try! keychain
.synchronizable(true)
.accessibility(.afterFirstUnlock)
.set("google.com_value2", key: "google.com_key2")
#endif
let allKeys = keychain.allKeys()
XCTAssertEqual(allKeys.count, 2)
XCTAssertEqual(allKeys.sorted(), ["google.com_key1", "google.com_key2"])
let allItems = keychain.allItems()
XCTAssertEqual(allItems.count, 2)
let sortedItems = allItems.sorted { (item1, item2) -> Bool in
let key1 = item1["key"] as! String
let key2 = item2["key"] as! String
return key1.compare(key2) == .orderedAscending || key1.compare(key2) == .orderedSame
}
#if !os(OSX)
XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
XCTAssertEqual(sortedItems[0]["value"] as? String, "google.com_value1")
XCTAssertEqual(sortedItems[0]["key"] as? String, "google.com_key1")
XCTAssertEqual(sortedItems[0]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[0]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[0]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[0]["protocol"] as? String, "HTTPS")
#if targetEnvironment(macCatalyst)
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AfterFirstUnlockThisDeviceOnly")
#else
XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AlwaysThisDeviceOnly")
#endif
XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "true")
XCTAssertEqual(sortedItems[1]["value"] as? String, "google.com_value2")
XCTAssertEqual(sortedItems[1]["key"] as? String, "google.com_key2")
XCTAssertEqual(sortedItems[1]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[1]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[1]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[1]["protocol"] as? String, "HTTPS")
#if targetEnvironment(macCatalyst)
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlock")
#else
XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "Always")
#endif
#else
XCTAssertEqual(sortedItems[0]["key"] as? String, "google.com_key1")
XCTAssertEqual(sortedItems[0]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[0]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[0]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[0]["protocol"] as? String, "HTTPS")
XCTAssertEqual(sortedItems[1]["key"] as? String, "google.com_key2")
XCTAssertEqual(sortedItems[1]["server"] as? String, "google.com")
XCTAssertEqual(sortedItems[1]["class"] as? String, "InternetPassword")
XCTAssertEqual(sortedItems[1]["authenticationType"] as? String, "Default")
XCTAssertEqual(sortedItems[1]["protocol"] as? String, "HTTPS")
#endif
}
#if !os(OSX)
do {
let allKeys = Keychain.allKeys(.genericPassword)
XCTAssertEqual(allKeys.count, 5)
let sortedKeys = allKeys.sorted { (key1, key2) -> Bool in
return key1.1.compare(key2.1) == .orderedAscending || key1.1.compare(key2.1) == .orderedSame
}
let service: String
#if targetEnvironment(macCatalyst)
service = "maccatalyst.com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"
#else
service = "com.kishikawakatsumi.KeychainAccess.TestHost"
#endif
XCTAssertEqual(sortedKeys[0].0, service)
XCTAssertEqual(sortedKeys[0].1, "key1")
XCTAssertEqual(sortedKeys[1].0, service)
XCTAssertEqual(sortedKeys[1].1, "key2")
XCTAssertEqual(sortedKeys[2].0, service)
XCTAssertEqual(sortedKeys[2].1, "key3")
XCTAssertEqual(sortedKeys[3].0, "service1")
XCTAssertEqual(sortedKeys[3].1, "service1_key1")
XCTAssertEqual(sortedKeys[4].0, "service1")
XCTAssertEqual(sortedKeys[4].1, "service1_key2")
}
do {
let allKeys = Keychain.allKeys(.internetPassword)
XCTAssertEqual(allKeys.count, 2)
let sortedKeys = allKeys.sorted { (key1, key2) -> Bool in
return key1.1.compare(key2.1) == .orderedAscending || key1.1.compare(key2.1) == .orderedSame
}
XCTAssertEqual(sortedKeys[0].0, "google.com")
XCTAssertEqual(sortedKeys[0].1, "google.com_key1")
XCTAssertEqual(sortedKeys[1].0, "google.com")
XCTAssertEqual(sortedKeys[1].1, "google.com_key2")
}
#endif
}
func testDescription() {
do {
let keychain = Keychain()
XCTAssertEqual(keychain.description, "[]")
XCTAssertEqual(keychain.debugDescription, "[]")
}
}
// MARK:
func testAuthenticationPolicy() {
guard #available(iOS 9.0, OSX 10.11, *) else {
return
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
#if os(iOS)
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence, .applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence, .applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet, .applicationPassword]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDCurrentSet, .applicationPassword, .privateKeyUsage]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .or, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.touchIDAny, .and, .devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertTrue(accessControl != nil)
}
#endif
#if os(OSX)
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.userPresence]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
do {
let accessibility: Accessibility = .whenPasscodeSetThisDeviceOnly
let policy: AuthenticationPolicy = [.devicePasscode]
let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
var error: Unmanaged?
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, flags, &error)
XCTAssertNil(error)
XCTAssertNotNil(accessControl)
}
#endif
}
func testIgnoringAttributeSynchronizable() {
let keychain = Keychain(service: "Twitter").synchronizable(false)
let keychainSynchronizable = Keychain(service: "Twitter").synchronizable(true)
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username", ignoringAttributeSynchronizable: false) } catch {}
do { try keychainSynchronizable.set("kishikawakatsumi_synchronizable", key: "username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertEqual(try! keychain.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
do { try keychain.set("password1234", key: "password", ignoringAttributeSynchronizable: false) } catch {}
do { try keychainSynchronizable.set("password1234_synchronizable", key: "password", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertEqual(try! keychain.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychain.get("password", ignoringAttributeSynchronizable: false), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "password1234_synchronizable", "stored password")
do { try keychain.remove("username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
do { try keychainSynchronizable.remove("username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertEqual(try! keychain.get("password", ignoringAttributeSynchronizable: false), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "password1234_synchronizable", "stored password")
do { try keychain.removeAll() } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
}
func testIgnoringAttributeSynchronizableBackwardCompatibility() {
let keychain = Keychain(service: "Twitter").synchronizable(false)
let keychainSynchronizable = Keychain(service: "Twitter").synchronizable(true)
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi", "stored username")
do { try keychainSynchronizable.set("kishikawakatsumi_synchronizable", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234", "stored password")
do { try keychainSynchronizable.set("password1234_synchronizable", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234_synchronizable", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234_synchronizable", "stored password")
do { try keychain.remove("username") } catch {}
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234_synchronizable", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234_synchronizable", "stored password")
do { try keychain.removeAll() } catch {}
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/AppDelegate.swift
================================================
//
// AppDelegate.swift
// TestHost-MacCatalyst
//
// Created by Kishikawa Katsumi on 2019/10/21.
// Copyright © 2019 Kishikawa Katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Base.lproj/LaunchScreen.storyboard
================================================
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Base.lproj/Main.storyboard
================================================
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
1
LSRequiresIPhoneOS
UIApplicationSceneManifest
UIApplicationSupportsMultipleScenes
UISceneConfigurations
UIWindowSceneSessionRoleApplication
UISceneConfigurationName
Default Configuration
UISceneDelegateClassName
$(PRODUCT_MODULE_NAME).SceneDelegate
UISceneStoryboardFile
Main
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Main
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/SceneDelegate.swift
================================================
//
// SceneDelegate.swift
// TestHost-MacCatalyst
//
// Created by Kishikawa Katsumi on 2019/10/21.
// Copyright © 2019 Kishikawa Katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/TestHost-MacCatalyst.entitlements
================================================
com.apple.security.app-sandbox
com.apple.security.network.client
keychain-access-groups
$(AppIdentifierPrefix)com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst
$(AppIdentifierPrefix)shared
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/ViewController.swift
================================================
//
// ViewController.swift
// TestHost-MacCatalyst
//
// Created by Kishikawa Katsumi on 2019/10/21.
// Copyright © 2019 Kishikawa Katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
14A98C4F235D284F00BBB893 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C4E235D284F00BBB893 /* AppDelegate.swift */; };
14A98C51235D284F00BBB893 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C50235D284F00BBB893 /* SceneDelegate.swift */; };
14A98C53235D284F00BBB893 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C52235D284F00BBB893 /* ViewController.swift */; };
14A98C56235D284F00BBB893 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14A98C54235D284F00BBB893 /* Main.storyboard */; };
14A98C58235D285000BBB893 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14A98C57235D285000BBB893 /* Assets.xcassets */; };
14A98C5B235D285000BBB893 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14A98C59235D285000BBB893 /* LaunchScreen.storyboard */; };
14A98C65235D286B00BBB893 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A98C64235D286B00BBB893 /* KeychainAccess.framework */; };
14A98C66235D286B00BBB893 /* KeychainAccess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14A98C64235D286B00BBB893 /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
14A98C88235D2AFA00BBB893 /* ErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C84235D2AFA00BBB893 /* ErrorTypeTests.swift */; };
14A98C8A235D2AFA00BBB893 /* KeychainAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C86235D2AFA00BBB893 /* KeychainAccessTests.swift */; };
14A98C8B235D2AFA00BBB893 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C87235D2AFA00BBB893 /* EnumTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
14A98C82235D293300BBB893 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14A98C43235D284F00BBB893 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 14A98C4A235D284F00BBB893;
remoteInfo = "TestHost-MacCatalyst";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
14A98C67235D286B00BBB893 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
14A98C66235D286B00BBB893 /* KeychainAccess.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
14A98C4B235D284F00BBB893 /* TestHost-MacCatalyst.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TestHost-MacCatalyst.app"; sourceTree = BUILT_PRODUCTS_DIR; };
14A98C4E235D284F00BBB893 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
14A98C50235D284F00BBB893 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
14A98C52235D284F00BBB893 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
14A98C55235D284F00BBB893 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
14A98C57235D285000BBB893 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
14A98C5A235D285000BBB893 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
14A98C5C235D285000BBB893 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
14A98C62235D286500BBB893 /* TestHost-MacCatalyst.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "TestHost-MacCatalyst.entitlements"; sourceTree = ""; };
14A98C64235D286B00BBB893 /* KeychainAccess.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KeychainAccess.framework; sourceTree = BUILT_PRODUCTS_DIR; };
14A98C7A235D292000BBB893 /* KeychainAccessTests-MacCatalyst.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "KeychainAccessTests-MacCatalyst.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
14A98C7E235D292000BBB893 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
14A98C84235D2AFA00BBB893 /* ErrorTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorTypeTests.swift; sourceTree = ""; };
14A98C86235D2AFA00BBB893 /* KeychainAccessTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainAccessTests.swift; sourceTree = ""; };
14A98C87235D2AFA00BBB893 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
14A98C48235D284F00BBB893 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14A98C65235D286B00BBB893 /* KeychainAccess.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14A98C77235D292000BBB893 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
14A98C42235D284F00BBB893 = {
isa = PBXGroup;
children = (
14A98C4D235D284F00BBB893 /* TestHost-MacCatalyst */,
14A98C7B235D292000BBB893 /* KeychainAccessTests-MacCatalyst */,
14A98C4C235D284F00BBB893 /* Products */,
14A98C63235D286B00BBB893 /* Frameworks */,
);
sourceTree = "";
};
14A98C4C235D284F00BBB893 /* Products */ = {
isa = PBXGroup;
children = (
14A98C4B235D284F00BBB893 /* TestHost-MacCatalyst.app */,
14A98C7A235D292000BBB893 /* KeychainAccessTests-MacCatalyst.xctest */,
);
name = Products;
sourceTree = "";
};
14A98C4D235D284F00BBB893 /* TestHost-MacCatalyst */ = {
isa = PBXGroup;
children = (
14A98C4E235D284F00BBB893 /* AppDelegate.swift */,
14A98C50235D284F00BBB893 /* SceneDelegate.swift */,
14A98C52235D284F00BBB893 /* ViewController.swift */,
14A98C54235D284F00BBB893 /* Main.storyboard */,
14A98C59235D285000BBB893 /* LaunchScreen.storyboard */,
14A98C57235D285000BBB893 /* Assets.xcassets */,
14A98C5C235D285000BBB893 /* Info.plist */,
14A98C62235D286500BBB893 /* TestHost-MacCatalyst.entitlements */,
);
path = "TestHost-MacCatalyst";
sourceTree = "";
};
14A98C63235D286B00BBB893 /* Frameworks */ = {
isa = PBXGroup;
children = (
14A98C64235D286B00BBB893 /* KeychainAccess.framework */,
);
name = Frameworks;
sourceTree = "";
};
14A98C7B235D292000BBB893 /* KeychainAccessTests-MacCatalyst */ = {
isa = PBXGroup;
children = (
14A98C86235D2AFA00BBB893 /* KeychainAccessTests.swift */,
14A98C87235D2AFA00BBB893 /* EnumTests.swift */,
14A98C84235D2AFA00BBB893 /* ErrorTypeTests.swift */,
14A98C7E235D292000BBB893 /* Info.plist */,
);
path = "KeychainAccessTests-MacCatalyst";
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
14A98C4A235D284F00BBB893 /* TestHost-MacCatalyst */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14A98C5F235D285000BBB893 /* Build configuration list for PBXNativeTarget "TestHost-MacCatalyst" */;
buildPhases = (
14A98C47235D284F00BBB893 /* Sources */,
14A98C48235D284F00BBB893 /* Frameworks */,
14A98C49235D284F00BBB893 /* Resources */,
14A98C67235D286B00BBB893 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "TestHost-MacCatalyst";
productName = "TestHost-MacCatalyst";
productReference = 14A98C4B235D284F00BBB893 /* TestHost-MacCatalyst.app */;
productType = "com.apple.product-type.application";
};
14A98C79235D292000BBB893 /* KeychainAccessTests-MacCatalyst */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14A98C7F235D292000BBB893 /* Build configuration list for PBXNativeTarget "KeychainAccessTests-MacCatalyst" */;
buildPhases = (
14A98C76235D292000BBB893 /* Sources */,
14A98C77235D292000BBB893 /* Frameworks */,
14A98C78235D292000BBB893 /* Resources */,
);
buildRules = (
);
dependencies = (
14A98C83235D293300BBB893 /* PBXTargetDependency */,
);
name = "KeychainAccessTests-MacCatalyst";
productName = "KeychainAccessTests-MacCatalyst";
productReference = 14A98C7A235D292000BBB893 /* KeychainAccessTests-MacCatalyst.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
14A98C43235D284F00BBB893 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1100;
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = "Kishikawa Katsumi";
TargetAttributes = {
14A98C4A235D284F00BBB893 = {
CreatedOnToolsVersion = 11.0;
};
14A98C79235D292000BBB893 = {
CreatedOnToolsVersion = 11.0;
LastSwiftMigration = 1100;
TestTargetID = 14A98C4A235D284F00BBB893;
};
};
};
buildConfigurationList = 14A98C46235D284F00BBB893 /* Build configuration list for PBXProject "TestHost-MacCatalyst" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 14A98C42235D284F00BBB893;
productRefGroup = 14A98C4C235D284F00BBB893 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
14A98C4A235D284F00BBB893 /* TestHost-MacCatalyst */,
14A98C79235D292000BBB893 /* KeychainAccessTests-MacCatalyst */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
14A98C49235D284F00BBB893 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A98C5B235D285000BBB893 /* LaunchScreen.storyboard in Resources */,
14A98C58235D285000BBB893 /* Assets.xcassets in Resources */,
14A98C56235D284F00BBB893 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14A98C78235D292000BBB893 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
14A98C47235D284F00BBB893 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A98C53235D284F00BBB893 /* ViewController.swift in Sources */,
14A98C4F235D284F00BBB893 /* AppDelegate.swift in Sources */,
14A98C51235D284F00BBB893 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14A98C76235D292000BBB893 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A98C88235D2AFA00BBB893 /* ErrorTypeTests.swift in Sources */,
14A98C8B235D2AFA00BBB893 /* EnumTests.swift in Sources */,
14A98C8A235D2AFA00BBB893 /* KeychainAccessTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
14A98C83235D293300BBB893 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 14A98C4A235D284F00BBB893 /* TestHost-MacCatalyst */;
targetProxy = 14A98C82235D293300BBB893 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
14A98C54235D284F00BBB893 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
14A98C55235D284F00BBB893 /* Base */,
);
name = Main.storyboard;
sourceTree = "";
};
14A98C59235D285000BBB893 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
14A98C5A235D285000BBB893 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
14A98C5D235D285000BBB893 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
14A98C5E235D285000BBB893 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
14A98C60235D285000BBB893 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "TestHost-MacCatalyst/TestHost-MacCatalyst.entitlements";
CODE_SIGN_STYLE = Automatic;
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "TestHost-MacCatalyst/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst";
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
14A98C61235D285000BBB893 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "TestHost-MacCatalyst/TestHost-MacCatalyst.entitlements";
CODE_SIGN_STYLE = Automatic;
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "TestHost-MacCatalyst/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst";
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
14A98C80235D292000BBB893 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "KeychainAccessTests-MacCatalyst/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccessTests-MacCatalyst";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost-MacCatalyst.app/TestHost-MacCatalyst";
};
name = Debug;
};
14A98C81235D292000BBB893 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "KeychainAccessTests-MacCatalyst/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccessTests-MacCatalyst";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost-MacCatalyst.app/TestHost-MacCatalyst";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
14A98C46235D284F00BBB893 /* Build configuration list for PBXProject "TestHost-MacCatalyst" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14A98C5D235D285000BBB893 /* Debug */,
14A98C5E235D285000BBB893 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
14A98C5F235D285000BBB893 /* Build configuration list for PBXNativeTarget "TestHost-MacCatalyst" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14A98C60235D285000BBB893 /* Debug */,
14A98C61235D285000BBB893 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
14A98C7F235D292000BBB893 /* Build configuration list for PBXNativeTarget "KeychainAccessTests-MacCatalyst" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14A98C80235D292000BBB893 /* Debug */,
14A98C81235D292000BBB893 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 14A98C43235D284F00BBB893 /* Project object */;
}
================================================
FILE: External/KeychainAccess/Lib/TestHost-MacCatalyst/TestHost-MacCatalyst.xcodeproj/xcshareddata/xcschemes/TestHost-MacCatalyst.xcscheme
================================================
================================================
FILE: External/KeychainAccess/Package.swift
================================================
// swift-tools-version:5.0
// Package.swift
// KeychainAccess
//
// Created by kishikawa katsumi on 2015/12/4.
// Copyright (c) 2015 kishikawa katsumi. All rights reserved.
//
import PackageDescription
let package = Package(
name: "KeychainAccess",
platforms: [
.macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2)
],
products: [
.library(name: "KeychainAccess", targets: ["KeychainAccess"])
],
targets: [
.target(name: "KeychainAccess", path: "Lib/KeychainAccess")
]
)
================================================
FILE: External/KeychainAccess/Package@swift-5.3.swift
================================================
// swift-tools-version:5.3
// Package.swift
// KeychainAccess
//
// Created by kishikawa katsumi on 2015/12/4.
// Copyright (c) 2015 kishikawa katsumi. All rights reserved.
//
import PackageDescription
let package = Package(
name: "KeychainAccess",
platforms: [
.macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2)
],
products: [
.library(name: "KeychainAccess", targets: ["KeychainAccess"])
],
targets: [
.target(name: "KeychainAccess", path: "Lib/KeychainAccess", exclude:["Info.plist"])
]
)
================================================
FILE: External/KeychainAccess/README.md
================================================
# KeychainAccess
[](https://travis-ci.com/kishikawakatsumi/KeychainAccess)
[](https://github.com/Carthage/Carthage)
[](https://swift.org/package-manager)
[](http://cocoadocs.org/docsets/KeychainAccess)
[](http://cocoadocs.org/docsets/KeychainAccess)
KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X. Makes using Keychain APIs extremely easy and much more palatable to use in Swift.
## :bulb: Features
- Simple interface
- Support access group
- [Support accessibility](#accessibility)
- [Support iCloud sharing](#icloud_sharing)
- **[Support TouchID and Keychain integration (iOS 8+)](#touch_id_integration)**
- **[Support Shared Web Credentials (iOS 8+)](#shared_web_credentials)**
- [Works on both iOS & macOS](#requirements)
- [watchOS and tvOS are supported](#requirements)
- **[Mac Catalyst is supported](#requirements)**
- **[Swift 3, 4 and 5 compatible](#requirements)**
## :book: Usage
##### :eyes: See also:
- [:link: iOS Example Project](https://github.com/kishikawakatsumi/KeychainAccess/tree/master/Examples/Example-iOS)
### :key: Basics
#### Saving Application Password
```swift
let keychain = Keychain(service: "com.example.github-token")
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
#### Saving Internet Password
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
### :key: Instantiation
#### Create Keychain for Application Password
```swift
let keychain = Keychain(service: "com.example.github-token")
```
```swift
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
```
#### Create Keychain for Internet Password
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
```
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https, authenticationType: .htmlForm)
```
### :key: Adding an item
#### subscripting
##### for String
```swift
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
```swift
keychain[string: "kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
##### for NSData
```swift
keychain[data: "secret"] = NSData(contentsOfFile: "secret.bin")
```
#### set method
```swift
keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
```
#### error handling
```swift
do {
try keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
}
catch let error {
print(error)
}
```
### :key: Obtaining an item
#### subscripting
##### for String (If the value is NSData, attempt to convert to String)
```swift
let token = keychain["kishikawakatsumi"]
```
```swift
let token = keychain[string: "kishikawakatsumi"]
```
##### for NSData
```swift
let secretData = keychain[data: "secret"]
```
#### get methods
##### as String
```swift
let token = try? keychain.get("kishikawakatsumi")
```
```swift
let token = try? keychain.getString("kishikawakatsumi")
```
##### as NSData
```swift
let data = try? keychain.getData("kishikawakatsumi")
```
### :key: Removing an item
#### subscripting
```swift
keychain["kishikawakatsumi"] = nil
```
#### remove method
```swift
do {
try keychain.remove("kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
### :key: Set Label and Comment
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
do {
try keychain
.label("github.com (kishikawakatsumi)")
.comment("github access token")
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
### :key: Obtaining Other Attributes
#### PersistentRef
```swift
let keychain = Keychain()
let persistentRef = keychain[attributes: "kishikawakatsumi"]?.persistentRef
...
```
#### Creation Date
```swift
let keychain = Keychain()
let creationDate = keychain[attributes: "kishikawakatsumi"]?.creationDate
...
```
#### All Attributes
```swift
let keychain = Keychain()
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
print(attributes?.comment)
print(attributes?.label)
print(attributes?.creator)
...
} catch let error {
print("error: \(error)")
}
```
##### subscripting
```swift
let keychain = Keychain()
if let attributes = keychain[attributes: "kishikawakatsumi"] {
print(attributes.comment)
print(attributes.label)
print(attributes.creator)
}
```
### :key: Configuration (Accessibility, Sharing, iCloud Sync)
**Provides fluent interfaces**
```swift
let keychain = Keychain(service: "com.example.github-token")
.label("github.com (kishikawakatsumi)")
.synchronizable(true)
.accessibility(.afterFirstUnlock)
```
#### Accessibility
##### Default accessibility matches background application (=kSecAttrAccessibleAfterFirstUnlock)
```swift
let keychain = Keychain(service: "com.example.github-token")
```
##### For background application
###### Creating instance
```swift
let keychain = Keychain(service: "com.example.github-token")
.accessibility(.afterFirstUnlock)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
###### One-shot
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain
.accessibility(.afterFirstUnlock)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
##### For foreground application
###### Creating instance
```swift
let keychain = Keychain(service: "com.example.github-token")
.accessibility(.whenUnlocked)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
###### One-shot
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain
.accessibility(.whenUnlocked)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
#### :couple: Sharing Keychain items
```swift
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
```
#### :arrows_counterclockwise: Synchronizing Keychain items with iCloud
###### Creating instance
```swift
let keychain = Keychain(service: "com.example.github-token")
.synchronizable(true)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
###### One-shot
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain
.synchronizable(true)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
### :cyclone: Touch ID (Face ID) integration
**Any Operation that require authentication must be run in the background thread.**
**If you run in the main thread, UI thread will lock for the system to try to display the authentication dialog.**
**To use Face ID, add `NSFaceIDUsageDescription` key to your `Info.plist`**
#### :closed_lock_with_key: Adding a Touch ID (Face ID) protected item
If you want to store the Touch ID protected Keychain item, specify `accessibility` and `authenticationPolicy` attributes.
```swift
let keychain = Keychain(service: "com.example.github-token")
DispatchQueue.global().async {
do {
// Should be the secret invalidated when passcode is removed? If not then use `.WhenUnlocked`
try keychain
.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny])
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
// Error handling if needed...
}
}
```
#### :closed_lock_with_key: Updating a Touch ID (Face ID) protected item
The same way as when adding.
**Do not run in the main thread if there is a possibility that the item you are trying to add already exists, and protected.**
**Because updating protected items requires authentication.**
Additionally, you want to show custom authentication prompt message when updating, specify an `authenticationPrompt` attribute.
If the item not protected, the `authenticationPrompt` parameter just be ignored.
```swift
let keychain = Keychain(service: "com.example.github-token")
DispatchQueue.global().async {
do {
// Should be the secret invalidated when passcode is removed? If not then use `.WhenUnlocked`
try keychain
.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny])
.authenticationPrompt("Authenticate to update your access token")
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
// Error handling if needed...
}
}
```
#### :closed_lock_with_key: Obtaining a Touch ID (Face ID) protected item
The same way as when you get a normal item. It will be displayed automatically Touch ID or passcode authentication If the item you try to get is protected.
If you want to show custom authentication prompt message, specify an `authenticationPrompt` attribute.
If the item not protected, the `authenticationPrompt` parameter just be ignored.
```swift
let keychain = Keychain(service: "com.example.github-token")
DispatchQueue.global().async {
do {
let password = try keychain
.authenticationPrompt("Authenticate to login to server")
.get("kishikawakatsumi")
print("password: \(password)")
} catch let error {
// Error handling if needed...
}
}
```
#### :closed_lock_with_key: Removing a Touch ID (Face ID) protected item
The same way as when you remove a normal item.
There is no way to show Touch ID or passcode authentication when removing Keychain items.
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain.remove("kishikawakatsumi")
} catch let error {
// Error handling if needed...
}
```
### :key: Shared Web Credentials
> Shared web credentials is a programming interface that enables native iOS apps to share credentials with their website counterparts. For example, a user may log in to a website in Safari, entering a user name and password, and save those credentials using the iCloud Keychain. Later, the user may run a native app from the same developer, and instead of the app requiring the user to reenter a user name and password, shared web credentials gives it access to the credentials that were entered earlier in Safari. The user can also create new accounts, update passwords, or delete her account from within the app. These changes are then saved and used by Safari.
```swift
let keychain = Keychain(server: "https://www.kishikawakatsumi.com", protocolType: .HTTPS)
let username = "kishikawakatsumi@mac.com"
// First, check the credential in the app's Keychain
if let password = try? keychain.get(username) {
// If found password in the Keychain,
// then log into the server
} else {
// If not found password in the Keychain,
// try to read from Shared Web Credentials
keychain.getSharedPassword(username) { (password, error) -> () in
if password != nil {
// If found password in the Shared Web Credentials,
// then log into the server
// and save the password to the Keychain
keychain[username] = password
} else {
// If not found password either in the Keychain also Shared Web Credentials,
// prompt for username and password
// Log into server
// If the login is successful,
// save the credentials to both the Keychain and the Shared Web Credentials.
keychain[username] = inputPassword
keychain.setSharedPassword(inputPassword, account: username)
}
}
}
```
#### Request all associated domain's credentials
```swift
Keychain.requestSharedWebCredential { (credentials, error) -> () in
}
```
#### Generate strong random password
Generate strong random password that is in the same format used by Safari autofill (xxx-xxx-xxx-xxx).
```swift
let password = Keychain.generatePassword() // => Nhu-GKm-s3n-pMx
```
#### How to set up Shared Web Credentials
> 1. Add a com.apple.developer.associated-domains entitlement to your app. This entitlement must include all the domains with which you want to share credentials.
>
> 2. Add an apple-app-site-association file to your website. This file must include application identifiers for all the apps with which the site wants to share credentials, and it must be properly signed.
>
> 3. When the app is installed, the system downloads and verifies the site association file for each of its associated domains. If the verification is successful, the app is associated with the domain.
**More details:**
### :mag: Debugging
#### Display all stored items if print keychain object
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
print("\(keychain)")
```
```
=>
[
[authenticationType: default, key: kishikawakatsumi, server: github.com, class: internetPassword, protocol: https]
[authenticationType: default, key: hirohamada, server: github.com, class: internetPassword, protocol: https]
[authenticationType: default, key: honeylemon, server: github.com, class: internetPassword, protocol: https]
]
```
#### Obtaining all stored keys
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
let keys = keychain.allKeys()
for key in keys {
print("key: \(key)")
}
```
```
=>
key: kishikawakatsumi
key: hirohamada
key: honeylemon
```
#### Obtaining all stored items
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
let items = keychain.allItems()
for item in items {
print("item: \(item)")
}
```
```
=>
item: [authenticationType: Default, key: kishikawakatsumi, server: github.com, class: InternetPassword, protocol: https]
item: [authenticationType: Default, key: hirohamada, server: github.com, class: InternetPassword, protocol: https]
item: [authenticationType: Default, key: honeylemon, server: github.com, class: InternetPassword, protocol: https]
```
## Keychain sharing capability
If you encounter the error below, you need to add an `Keychain.entitlements`.
```
OSStatus error:[-34018] Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements.
```
## Requirements
| | OS | Swift |
|------------|------------------------------------------------------------|--------------------|
| **v1.1.x** | iOS 7+, macOS 10.9+ | 1.1 |
| **v1.2.x** | iOS 7+, macOS 10.9+ | 1.2 |
| **v2.0.x** | iOS 7+, macOS 10.9+, watchOS 2+ | 2.0 |
| **v2.1.x** | iOS 7+, macOS 10.9+, watchOS 2+ | 2.0 |
| **v2.2.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1 |
| **v2.3.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1, 2.2 |
| **v2.4.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.2, 2.3 |
| **v3.0.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 3.x |
| **v3.1.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2 |
| **v3.2.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2, 5.0 |
| **v4.0.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2, 5.1 |
| **v4.1.x** | iOS 8+, macOS 10.9+, watchOS 3+, tvOS 9+, Mac Catalyst 13+ | 4.0, 4.1, 4.2, 5.1 |
## Installation
### CocoaPods
KeychainAccess is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following lines to your Podfile:
```ruby
use_frameworks!
pod 'KeychainAccess'
```
### Carthage
KeychainAccess is available through [Carthage](https://github.com/Carthage/Carthage). To install
it, simply add the following line to your Cartfile:
`github "kishikawakatsumi/KeychainAccess"`
### Swift Package Manager
KeychainAccess is also available through [Swift Package Manager](https://github.com/apple/swift-package-manager/).
#### Xcode
Select `File > Add Packages... > Add Package Dependency...`,
#### CLI
First, create `Package.swift` that its package declaration includes:
```swift
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "MyLibrary",
products: [
.library(name: "MyLibrary", targets: ["MyLibrary"]),
],
dependencies: [
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "3.0.0"),
],
targets: [
.target(name: "MyLibrary", dependencies: ["KeychainAccess"]),
]
)
```
Then, type
```shell
$ swift build
```
### To manually add to your project
1. Add `Lib/KeychainAccess.xcodeproj` to your project
2. Link `KeychainAccess.framework` with your target
3. Add `Copy Files Build Phase` to include the framework to your application bundle
_See [iOS Example Project](https://github.com/kishikawakatsumi/KeychainAccess/tree/master/Examples/Example-iOS) as reference._
## Author
kishikawa katsumi, kishikawakatsumi@mac.com
## License
KeychainAccess is available under the MIT license. See the LICENSE file for more info.
================================================
FILE: External/KeychainAccess/Sources/Keychain.swift
================================================
//
// Keychain.swift
// KeychainAccess
//
// Created by kishikawa katsumi on 2014/12/24.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import Security
#if os(iOS) || os(OSX)
import LocalAuthentication
#endif
public let KeychainAccessErrorDomain = "com.kishikawakatsumi.KeychainAccess.error"
public enum ItemClass {
case genericPassword
case internetPassword
}
public enum ProtocolType {
case ftp
case ftpAccount
case http
case irc
case nntp
case pop3
case smtp
case socks
case imap
case ldap
case appleTalk
case afp
case telnet
case ssh
case ftps
case https
case httpProxy
case httpsProxy
case ftpProxy
case smb
case rtsp
case rtspProxy
case daap
case eppc
case ipp
case nntps
case ldaps
case telnetS
case imaps
case ircs
case pop3S
}
public enum AuthenticationType {
case ntlm
case msn
case dpa
case rpa
case httpBasic
case httpDigest
case htmlForm
case `default`
}
public enum Accessibility {
/**
Item data can only be accessed
while the device is unlocked. This is recommended for items that only
need be accesible while the application is in the foreground. Items
with this attribute will migrate to a new device when using encrypted
backups.
*/
case whenUnlocked
/**
Item data can only be
accessed once the device has been unlocked after a restart. This is
recommended for items that need to be accesible by background
applications. Items with this attribute will migrate to a new device
when using encrypted backups.
*/
case afterFirstUnlock
/**
Item data can always be accessed
regardless of the lock state of the device. This is not recommended
for anything except system use. Items with this attribute will migrate
to a new device when using encrypted backups.
*/
@available(macCatalyst, unavailable)
case always
/**
Item data can
only be accessed while the device is unlocked. This class is only
available if a passcode is set on the device. This is recommended for
items that only need to be accessible while the application is in the
foreground. Items with this attribute will never migrate to a new
device, so after a backup is restored to a new device, these items
will be missing. No items can be stored in this class on devices
without a passcode. Disabling the device passcode will cause all
items in this class to be deleted.
*/
@available(iOS 8.0, OSX 10.10, *)
case whenPasscodeSetThisDeviceOnly
/**
Item data can only
be accessed while the device is unlocked. This is recommended for items
that only need be accesible while the application is in the foreground.
Items with this attribute will never migrate to a new device, so after
a backup is restored to a new device, these items will be missing.
*/
case whenUnlockedThisDeviceOnly
/**
Item data can
only be accessed once the device has been unlocked after a restart.
This is recommended for items that need to be accessible by background
applications. Items with this attribute will never migrate to a new
device, so after a backup is restored to a new device these items will
be missing.
*/
case afterFirstUnlockThisDeviceOnly
/**
Item data can always
be accessed regardless of the lock state of the device. This option
is not recommended for anything except system use. Items with this
attribute will never migrate to a new device, so after a backup is
restored to a new device, these items will be missing.
*/
@available(macCatalyst, unavailable)
case alwaysThisDeviceOnly
}
/**
Predefined item attribute constants used to get or set values
in a dictionary. The kSecUseAuthenticationUI constant is the key and its
value is one of the constants defined here.
If the key kSecUseAuthenticationUI not provided then kSecUseAuthenticationUIAllow
is used as default.
*/
public enum AuthenticationUI {
/**
Specifies that authenticate UI can appear.
*/
case allow
/**
Specifies that the error
errSecInteractionNotAllowed will be returned if an item needs
to authenticate with UI
*/
case fail
/**
Specifies that all items which need
to authenticate with UI will be silently skipped. This value can be used
only with SecItemCopyMatching.
*/
case skip
}
@available(iOS 9.0, OSX 10.11, *)
extension AuthenticationUI {
public var rawValue: String {
switch self {
case .allow:
return UseAuthenticationUIAllow
case .fail:
return UseAuthenticationUIFail
case .skip:
return UseAuthenticationUISkip
}
}
public var description: String {
switch self {
case .allow:
return "allow"
case .fail:
return "fail"
case .skip:
return "skip"
}
}
}
public struct AuthenticationPolicy: OptionSet {
/**
User presence policy using Touch ID or Passcode. Touch ID does not
have to be available or enrolled. Item is still accessible by Touch ID
even if fingers are added or removed.
*/
@available(iOS 8.0, OSX 10.10, watchOS 2.0, tvOS 8.0, *)
public static let userPresence = AuthenticationPolicy(rawValue: 1 << 0)
/**
Constraint: Touch ID (any finger) or Face ID. Touch ID or Face ID must be available. With Touch ID
at least one finger must be enrolled. With Face ID user has to be enrolled. Item is still accessible by Touch ID even
if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled.
*/
@available(iOS 11.3, OSX 10.13.4, watchOS 4.3, tvOS 11.3, *)
public static let biometryAny = AuthenticationPolicy(rawValue: 1 << 1)
/**
Deprecated, please use biometryAny instead.
*/
@available(iOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryAny")
@available(OSX, introduced: 10.12.1, deprecated: 10.13.4, renamed: "biometryAny")
@available(watchOS, introduced: 2.0, deprecated: 4.3, renamed: "biometryAny")
@available(tvOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryAny")
public static let touchIDAny = AuthenticationPolicy(rawValue: 1 << 1)
/**
Constraint: Touch ID from the set of currently enrolled fingers. Touch ID must be available and at least one finger must
be enrolled. When fingers are added or removed, the item is invalidated. When Face ID is re-enrolled this item is invalidated.
*/
@available(iOS 11.3, OSX 10.13, watchOS 4.3, tvOS 11.3, *)
public static let biometryCurrentSet = AuthenticationPolicy(rawValue: 1 << 3)
/**
Deprecated, please use biometryCurrentSet instead.
*/
@available(iOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryCurrentSet")
@available(OSX, introduced: 10.12.1, deprecated: 10.13.4, renamed: "biometryCurrentSet")
@available(watchOS, introduced: 2.0, deprecated: 4.3, renamed: "biometryCurrentSet")
@available(tvOS, introduced: 9.0, deprecated: 11.3, renamed: "biometryCurrentSet")
public static let touchIDCurrentSet = AuthenticationPolicy(rawValue: 1 << 3)
/**
Constraint: Device passcode
*/
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
public static let devicePasscode = AuthenticationPolicy(rawValue: 1 << 4)
/**
Constraint: Watch
*/
@available(iOS, unavailable)
@available(OSX 10.15, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
public static let watch = AuthenticationPolicy(rawValue: 1 << 5)
/**
Constraint logic operation: when using more than one constraint,
at least one of them must be satisfied.
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let or = AuthenticationPolicy(rawValue: 1 << 14)
/**
Constraint logic operation: when using more than one constraint,
all must be satisfied.
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let and = AuthenticationPolicy(rawValue: 1 << 15)
/**
Create access control for private key operations (i.e. sign operation)
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let privateKeyUsage = AuthenticationPolicy(rawValue: 1 << 30)
/**
Security: Application provided password for data encryption key generation.
This is not a constraint but additional item encryption mechanism.
*/
@available(iOS 9.0, OSX 10.12.1, watchOS 2.0, tvOS 9.0, *)
public static let applicationPassword = AuthenticationPolicy(rawValue: 1 << 31)
#if swift(>=2.3)
public let rawValue: UInt
public init(rawValue: UInt) {
self.rawValue = rawValue
}
#else
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
#endif
}
public struct Attributes {
public var `class`: String? {
return attributes[Class] as? String
}
public var data: Data? {
return attributes[ValueData] as? Data
}
public var ref: Data? {
return attributes[ValueRef] as? Data
}
public var persistentRef: Data? {
return attributes[ValuePersistentRef] as? Data
}
public var accessible: String? {
return attributes[AttributeAccessible] as? String
}
public var accessControl: SecAccessControl? {
if #available(OSX 10.10, *) {
if let accessControl = attributes[AttributeAccessControl] {
return (accessControl as! SecAccessControl)
}
return nil
} else {
return nil
}
}
public var accessGroup: String? {
return attributes[AttributeAccessGroup] as? String
}
public var synchronizable: Bool? {
return attributes[AttributeSynchronizable] as? Bool
}
public var creationDate: Date? {
return attributes[AttributeCreationDate] as? Date
}
public var modificationDate: Date? {
return attributes[AttributeModificationDate] as? Date
}
public var attributeDescription: String? {
return attributes[AttributeDescription] as? String
}
public var comment: String? {
return attributes[AttributeComment] as? String
}
public var creator: String? {
return attributes[AttributeCreator] as? String
}
public var type: String? {
return attributes[AttributeType] as? String
}
public var label: String? {
return attributes[AttributeLabel] as? String
}
public var isInvisible: Bool? {
return attributes[AttributeIsInvisible] as? Bool
}
public var isNegative: Bool? {
return attributes[AttributeIsNegative] as? Bool
}
public var account: String? {
return attributes[AttributeAccount] as? String
}
public var service: String? {
return attributes[AttributeService] as? String
}
public var generic: Data? {
return attributes[AttributeGeneric] as? Data
}
public var securityDomain: String? {
return attributes[AttributeSecurityDomain] as? String
}
public var server: String? {
return attributes[AttributeServer] as? String
}
public var `protocol`: String? {
return attributes[AttributeProtocol] as? String
}
public var authenticationType: String? {
return attributes[AttributeAuthenticationType] as? String
}
public var port: Int? {
return attributes[AttributePort] as? Int
}
public var path: String? {
return attributes[AttributePath] as? String
}
fileprivate let attributes: [String: Any]
init(attributes: [String: Any]) {
self.attributes = attributes
}
public subscript(key: String) -> Any? {
get {
return attributes[key]
}
}
}
public final class Keychain {
public var itemClass: ItemClass {
return options.itemClass
}
public var service: String {
return options.service
}
// This attribute (kSecAttrAccessGroup) applies to macOS keychain items only if you also set a value of true for the
// kSecUseDataProtectionKeychain key, the kSecAttrSynchronizable key, or both.
public var accessGroup: String? {
return options.accessGroup
}
public var server: URL {
return options.server
}
public var protocolType: ProtocolType {
return options.protocolType
}
public var authenticationType: AuthenticationType {
return options.authenticationType
}
public var accessibility: Accessibility {
return options.accessibility
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public var authenticationPolicy: AuthenticationPolicy? {
return options.authenticationPolicy
}
public var synchronizable: Bool {
return options.synchronizable
}
public var label: String? {
return options.label
}
public var comment: String? {
return options.comment
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public var authenticationPrompt: String? {
return options.authenticationPrompt
}
@available(iOS 9.0, OSX 10.11, *)
public var authenticationUI: AuthenticationUI {
return options.authenticationUI ?? .allow
}
#if os(iOS) || os(OSX)
@available(iOS 9.0, OSX 10.11, *)
public var authenticationContext: LAContext? {
return options.authenticationContext as? LAContext
}
#endif
fileprivate let options: Options
// MARK:
public convenience init() {
var options = Options()
if let bundleIdentifier = Bundle.main.bundleIdentifier {
options.service = bundleIdentifier
}
self.init(options)
}
public convenience init(service: String) {
var options = Options()
options.service = service
self.init(options)
}
public convenience init(accessGroup: String) {
var options = Options()
if let bundleIdentifier = Bundle.main.bundleIdentifier {
options.service = bundleIdentifier
}
options.accessGroup = accessGroup
self.init(options)
}
public convenience init(service: String, accessGroup: String) {
var options = Options()
options.service = service
options.accessGroup = accessGroup
self.init(options)
}
public convenience init(server: String, protocolType: ProtocolType, accessGroup: String? = nil, authenticationType: AuthenticationType = .default) {
self.init(server: URL(string: server)!, protocolType: protocolType, accessGroup: accessGroup, authenticationType: authenticationType)
}
public convenience init(server: URL, protocolType: ProtocolType, accessGroup: String? = nil, authenticationType: AuthenticationType = .default) {
var options = Options()
options.itemClass = .internetPassword
options.server = server
options.protocolType = protocolType
options.accessGroup = accessGroup
options.authenticationType = authenticationType
self.init(options)
}
fileprivate init(_ opts: Options) {
options = opts
}
// MARK:
public func accessibility(_ accessibility: Accessibility) -> Keychain {
var options = self.options
options.accessibility = accessibility
return Keychain(options)
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public func accessibility(_ accessibility: Accessibility, authenticationPolicy: AuthenticationPolicy) -> Keychain {
var options = self.options
options.accessibility = accessibility
options.authenticationPolicy = authenticationPolicy
return Keychain(options)
}
public func synchronizable(_ synchronizable: Bool) -> Keychain {
var options = self.options
options.synchronizable = synchronizable
return Keychain(options)
}
public func label(_ label: String) -> Keychain {
var options = self.options
options.label = label
return Keychain(options)
}
public func comment(_ comment: String) -> Keychain {
var options = self.options
options.comment = comment
return Keychain(options)
}
public func attributes(_ attributes: [String: Any]) -> Keychain {
var options = self.options
attributes.forEach { options.attributes.updateValue($1, forKey: $0) }
return Keychain(options)
}
@available(iOS 8.0, OSX 10.10, *)
@available(watchOS, unavailable)
public func authenticationPrompt(_ authenticationPrompt: String) -> Keychain {
var options = self.options
options.authenticationPrompt = authenticationPrompt
return Keychain(options)
}
@available(iOS 9.0, OSX 10.11, *)
public func authenticationUI(_ authenticationUI: AuthenticationUI) -> Keychain {
var options = self.options
options.authenticationUI = authenticationUI
return Keychain(options)
}
#if os(iOS) || os(OSX)
@available(iOS 9.0, OSX 10.11, *)
public func authenticationContext(_ authenticationContext: LAContext) -> Keychain {
var options = self.options
options.authenticationContext = authenticationContext
return Keychain(options)
}
#endif
// MARK:
public func get(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
return try getString(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}
public func getString(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
guard let data = try getData(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable) else {
return nil
}
guard let string = String(data: data, encoding: .utf8) else {
print("failed to convert data to string")
throw Status.conversionError
}
return string
}
public func getData(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> Data? {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[MatchLimit] = MatchLimitOne
query[ReturnData] = kCFBooleanTrue
query[AttributeAccount] = key
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
guard let data = result as? Data else {
throw Status.unexpectedError
}
return data
case errSecItemNotFound:
return nil
default:
throw securityError(status: status)
}
}
public func get(_ key: String, ignoringAttributeSynchronizable: Bool = true, handler: (Attributes?) -> T) throws -> T {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[MatchLimit] = MatchLimitOne
query[ReturnData] = kCFBooleanTrue
query[ReturnAttributes] = kCFBooleanTrue
query[ReturnRef] = kCFBooleanTrue
query[ReturnPersistentRef] = kCFBooleanTrue
query[AttributeAccount] = key
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
guard let attributes = result as? [String: Any] else {
throw Status.unexpectedError
}
return handler(Attributes(attributes: attributes))
case errSecItemNotFound:
return handler(nil)
default:
throw securityError(status: status)
}
}
// MARK:
public func set(_ value: String, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
guard let data = value.data(using: .utf8, allowLossyConversion: false) else {
print("failed to convert string to data")
throw Status.conversionError
}
try set(data, key: key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}
public func set(_ value: Data, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[AttributeAccount] = key
#if os(iOS)
if #available(iOS 9.0, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
} else {
query[UseNoAuthenticationUI] = kCFBooleanTrue
}
#elseif os(OSX)
query[ReturnData] = kCFBooleanTrue
if #available(OSX 10.11, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
}
#else
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
}
#endif
var status = SecItemCopyMatching(query as CFDictionary, nil)
switch status {
case errSecSuccess, errSecInteractionNotAllowed:
var query = options.query()
query[AttributeAccount] = key
var (attributes, error) = options.attributes(key: nil, value: value)
if let error = error {
print(error.localizedDescription)
throw error
}
options.attributes.forEach { attributes.updateValue($1, forKey: $0) }
#if os(iOS)
if status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_8_0) {
try remove(key)
try set(value, key: key)
} else {
status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
if status != errSecSuccess {
throw securityError(status: status)
}
}
#else
status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
if status != errSecSuccess {
throw securityError(status: status)
}
#endif
case errSecItemNotFound:
var (attributes, error) = options.attributes(key: key, value: value)
if let error = error {
print(error.localizedDescription)
throw error
}
options.attributes.forEach { attributes.updateValue($1, forKey: $0) }
status = SecItemAdd(attributes as CFDictionary, nil)
if status != errSecSuccess {
throw securityError(status: status)
}
default:
throw securityError(status: status)
}
}
public subscript(key: String) -> String? {
get {
#if swift(>=5.0)
return try? get(key)
#else
return (try? get(key)).flatMap { $0 }
#endif
}
set {
if let value = newValue {
do {
try set(value, key: key)
} catch {}
} else {
do {
try remove(key)
} catch {}
}
}
}
public subscript(string key: String) -> String? {
get {
return self[key]
}
set {
self[key] = newValue
}
}
public subscript(data key: String) -> Data? {
get {
#if swift(>=5.0)
return try? getData(key)
#else
return (try? getData(key)).flatMap { $0 }
#endif
}
set {
if let value = newValue {
do {
try set(value, key: key)
} catch {}
} else {
do {
try remove(key)
} catch {}
}
}
}
public subscript(attributes key: String) -> Attributes? {
get {
#if swift(>=5.0)
return try? get(key) { $0 }
#else
return (try? get(key) { $0 }).flatMap { $0 }
#endif
}
}
// MARK:
public func remove(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[AttributeAccount] = key
let status = SecItemDelete(query as CFDictionary)
if status != errSecSuccess && status != errSecItemNotFound {
throw securityError(status: status)
}
}
public func removeAll() throws {
var query = options.query()
#if !os(iOS) && !os(watchOS) && !os(tvOS)
query[MatchLimit] = MatchLimitAll
#endif
let status = SecItemDelete(query as CFDictionary)
if status != errSecSuccess && status != errSecItemNotFound {
throw securityError(status: status)
}
}
// MARK:
public func contains(_ key: String, withoutAuthenticationUI: Bool = false) throws -> Bool {
var query = options.query()
query[AttributeAccount] = key
if withoutAuthenticationUI {
#if os(iOS) || os(watchOS) || os(tvOS)
if #available(iOS 9.0, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
} else {
query[UseNoAuthenticationUI] = kCFBooleanTrue
}
#else
if #available(OSX 10.11, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
} else {
query[UseAuthenticationUI] = UseAuthenticationUIFail
}
} else if #available(OSX 10.10, *) {
query[UseNoAuthenticationUI] = kCFBooleanTrue
}
#endif
} else {
if #available(iOS 9.0, OSX 10.11, *) {
if let authenticationUI = options.authenticationUI {
query[UseAuthenticationUI] = authenticationUI.rawValue
}
}
}
let status = SecItemCopyMatching(query as CFDictionary, nil)
switch status {
case errSecSuccess:
return true
case errSecInteractionNotAllowed:
if withoutAuthenticationUI {
return true
}
return false
case errSecItemNotFound:
return false
default:
throw securityError(status: status)
}
}
// MARK:
public class func allKeys(_ itemClass: ItemClass) -> [(String, String)] {
var query = [String: Any]()
query[Class] = itemClass.rawValue
query[AttributeSynchronizable] = SynchronizableAny
query[MatchLimit] = MatchLimitAll
query[ReturnAttributes] = kCFBooleanTrue
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
if let items = result as? [[String: Any]] {
return prettify(itemClass: itemClass, items: items).map {
switch itemClass {
case .genericPassword:
return (($0["service"] ?? "") as! String, ($0["key"] ?? "") as! String)
case .internetPassword:
return (($0["server"] ?? "") as! String, ($0["key"] ?? "") as! String)
}
}
}
case errSecItemNotFound:
return []
default: ()
}
securityError(status: status)
return []
}
public func allKeys() -> [String] {
let allItems = type(of: self).prettify(itemClass: itemClass, items: items())
let filter: ([String: Any]) -> String? = { $0["key"] as? String }
#if swift(>=4.1)
return allItems.compactMap(filter)
#else
return allItems.flatMap(filter)
#endif
}
public class func allItems(_ itemClass: ItemClass) -> [[String: Any]] {
var query = [String: Any]()
query[Class] = itemClass.rawValue
query[MatchLimit] = MatchLimitAll
query[ReturnAttributes] = kCFBooleanTrue
#if os(iOS) || os(watchOS) || os(tvOS)
query[ReturnData] = kCFBooleanTrue
#endif
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
if let items = result as? [[String: Any]] {
return prettify(itemClass: itemClass, items: items)
}
case errSecItemNotFound:
return []
default: ()
}
securityError(status: status)
return []
}
public func allItems() -> [[String: Any]] {
return type(of: self).prettify(itemClass: itemClass, items: items())
}
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func getSharedPassword(_ completion: @escaping (_ account: String?, _ password: String?, _ error: Error?) -> () = { account, password, error -> () in }) {
if let domain = server.host {
type(of: self).requestSharedWebCredential(domain: domain, account: nil) { (credentials, error) -> () in
if let credential = credentials.first {
let account = credential["account"]
let password = credential["password"]
completion(account, password, error)
} else {
completion(nil, nil, error)
}
}
} else {
let error = securityError(status: Status.param.rawValue)
completion(nil, nil, error)
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func getSharedPassword(_ account: String, completion: @escaping (_ password: String?, _ error: Error?) -> () = { password, error -> () in }) {
if let domain = server.host {
type(of: self).requestSharedWebCredential(domain: domain, account: account) { (credentials, error) -> () in
if let credential = credentials.first {
if let password = credential["password"] {
completion(password, error)
} else {
completion(nil, error)
}
} else {
completion(nil, error)
}
}
} else {
let error = securityError(status: Status.param.rawValue)
completion(nil, error)
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func setSharedPassword(_ password: String, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
setSharedPassword(password as String?, account: account, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
fileprivate func setSharedPassword(_ password: String?, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
if let domain = server.host {
SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { error -> () in
if let error = error {
completion(error.error)
} else {
completion(nil)
}
}
} else {
let error = securityError(status: Status.param.rawValue)
completion(error)
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public func removeSharedPassword(_ account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) {
setSharedPassword(nil, account: account, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public class func requestSharedWebCredential(_ completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
requestSharedWebCredential(domain: nil, account: nil, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public class func requestSharedWebCredential(domain: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
requestSharedWebCredential(domain: domain, account: nil, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
public class func requestSharedWebCredential(domain: String, account: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) {
requestSharedWebCredential(domain: Optional(domain), account: Optional(account)!, completion: completion)
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
@available(iOS 8.0, *)
fileprivate class func requestSharedWebCredential(domain: String?, account: String?, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> ()) {
SecRequestSharedWebCredential(domain as CFString?, account as CFString?) { (credentials, error) -> () in
var remoteError: NSError?
if let error = error {
remoteError = error.error
if remoteError?.code != Int(errSecItemNotFound) {
print("error:[\(remoteError!.code)] \(remoteError!.localizedDescription)")
}
}
if let credentials = credentials {
let credentials = (credentials as NSArray).map { credentials -> [String: String] in
var credential = [String: String]()
if let credentials = credentials as? [String: String] {
if let server = credentials[AttributeServer] {
credential["server"] = server
}
if let account = credentials[AttributeAccount] {
credential["account"] = account
}
if let password = credentials[SharedPassword] {
credential["password"] = password
}
}
return credential
}
completion(credentials, remoteError)
} else {
completion([], remoteError)
}
}
}
#endif
#if os(iOS) && !targetEnvironment(macCatalyst)
/**
@abstract Returns a randomly generated password.
@return String password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present.
*/
@available(iOS 8.0, *)
public class func generatePassword() -> String {
return SecCreateSharedWebCredentialPassword()! as String
}
#endif
// MARK:
fileprivate func items() -> [[String: Any]] {
var query = options.query()
query[MatchLimit] = MatchLimitAll
query[ReturnAttributes] = kCFBooleanTrue
#if os(iOS) || os(watchOS) || os(tvOS)
query[ReturnData] = kCFBooleanTrue
#endif
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
if let items = result as? [[String: Any]] {
return items
}
case errSecItemNotFound:
return []
default: ()
}
securityError(status: status)
return []
}
fileprivate class func prettify(itemClass: ItemClass, items: [[String: Any]]) -> [[String: Any]] {
let items = items.map { attributes -> [String: Any] in
var item = [String: Any]()
item["class"] = itemClass.description
if let accessGroup = attributes[AttributeAccessGroup] as? String {
item["accessGroup"] = accessGroup
}
switch itemClass {
case .genericPassword:
if let service = attributes[AttributeService] as? String {
item["service"] = service
}
case .internetPassword:
if let server = attributes[AttributeServer] as? String {
item["server"] = server
}
if let proto = attributes[AttributeProtocol] as? String {
if let protocolType = ProtocolType(rawValue: proto) {
item["protocol"] = protocolType.description
}
}
if let auth = attributes[AttributeAuthenticationType] as? String {
if let authenticationType = AuthenticationType(rawValue: auth) {
item["authenticationType"] = authenticationType.description
}
}
}
if let key = attributes[AttributeAccount] as? String {
item["key"] = key
}
if let data = attributes[ValueData] as? Data {
if let text = String(data: data, encoding: .utf8) {
item["value"] = text
} else {
item["value"] = data
}
}
if let accessible = attributes[AttributeAccessible] as? String {
if let accessibility = Accessibility(rawValue: accessible) {
item["accessibility"] = accessibility.description
}
}
if let synchronizable = attributes[AttributeSynchronizable] as? Bool {
item["synchronizable"] = synchronizable ? "true" : "false"
}
return item
}
return items
}
// MARK:
@discardableResult
fileprivate class func securityError(status: OSStatus) -> Error {
let error = Status(status: status)
if error != .userCanceled {
print("OSStatus error:[\(error.errorCode)] \(error.description)")
}
return error
}
@discardableResult
fileprivate func securityError(status: OSStatus) -> Error {
return type(of: self).securityError(status: status)
}
}
struct Options {
var itemClass: ItemClass = .genericPassword
var service: String = ""
var accessGroup: String? = nil
var server: URL!
var protocolType: ProtocolType!
var authenticationType: AuthenticationType = .default
var accessibility: Accessibility = .afterFirstUnlock
var authenticationPolicy: AuthenticationPolicy?
var synchronizable: Bool = false
var label: String?
var comment: String?
var authenticationPrompt: String?
var authenticationUI: AuthenticationUI?
var authenticationContext: AnyObject?
var attributes = [String: Any]()
}
/** Class Key Constant */
private let Class = String(kSecClass)
/** Attribute Key Constants */
private let AttributeAccessible = String(kSecAttrAccessible)
@available(iOS 8.0, OSX 10.10, *)
private let AttributeAccessControl = String(kSecAttrAccessControl)
private let AttributeAccessGroup = String(kSecAttrAccessGroup)
private let AttributeSynchronizable = String(kSecAttrSynchronizable)
private let AttributeCreationDate = String(kSecAttrCreationDate)
private let AttributeModificationDate = String(kSecAttrModificationDate)
private let AttributeDescription = String(kSecAttrDescription)
private let AttributeComment = String(kSecAttrComment)
private let AttributeCreator = String(kSecAttrCreator)
private let AttributeType = String(kSecAttrType)
private let AttributeLabel = String(kSecAttrLabel)
private let AttributeIsInvisible = String(kSecAttrIsInvisible)
private let AttributeIsNegative = String(kSecAttrIsNegative)
private let AttributeAccount = String(kSecAttrAccount)
private let AttributeService = String(kSecAttrService)
private let AttributeGeneric = String(kSecAttrGeneric)
private let AttributeSecurityDomain = String(kSecAttrSecurityDomain)
private let AttributeServer = String(kSecAttrServer)
private let AttributeProtocol = String(kSecAttrProtocol)
private let AttributeAuthenticationType = String(kSecAttrAuthenticationType)
private let AttributePort = String(kSecAttrPort)
private let AttributePath = String(kSecAttrPath)
private let SynchronizableAny = kSecAttrSynchronizableAny
/** Search Constants */
private let MatchLimit = String(kSecMatchLimit)
private let MatchLimitOne = kSecMatchLimitOne
private let MatchLimitAll = kSecMatchLimitAll
/** Return Type Key Constants */
private let ReturnData = String(kSecReturnData)
private let ReturnAttributes = String(kSecReturnAttributes)
private let ReturnRef = String(kSecReturnRef)
private let ReturnPersistentRef = String(kSecReturnPersistentRef)
/** Value Type Key Constants */
private let ValueData = String(kSecValueData)
private let ValueRef = String(kSecValueRef)
private let ValuePersistentRef = String(kSecValuePersistentRef)
/** Other Constants */
@available(iOS 8.0, OSX 10.10, tvOS 8.0, *)
private let UseOperationPrompt = String(kSecUseOperationPrompt)
@available(iOS, introduced: 8.0, deprecated: 9.0, message: "Use a UseAuthenticationUI instead.")
@available(OSX, introduced: 10.10, deprecated: 10.11, message: "Use UseAuthenticationUI instead.")
@available(watchOS, introduced: 2.0, deprecated: 2.0, message: "Use UseAuthenticationUI instead.")
@available(tvOS, introduced: 8.0, deprecated: 9.0, message: "Use UseAuthenticationUI instead.")
private let UseNoAuthenticationUI = String(kSecUseNoAuthenticationUI)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUI = String(kSecUseAuthenticationUI)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationContext = String(kSecUseAuthenticationContext)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUIAllow = String(kSecUseAuthenticationUIAllow)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUIFail = String(kSecUseAuthenticationUIFail)
@available(iOS 9.0, OSX 10.11, watchOS 2.0, tvOS 9.0, *)
private let UseAuthenticationUISkip = String(kSecUseAuthenticationUISkip)
#if os(iOS) && !targetEnvironment(macCatalyst)
/** Credential Key Constants */
private let SharedPassword = String(kSecSharedPassword)
#endif
extension Keychain: CustomStringConvertible, CustomDebugStringConvertible {
public var description: String {
let items = allItems()
if items.isEmpty {
return "[]"
}
var description = "[\n"
for item in items {
description += " "
description += "\(item)\n"
}
description += "]"
return description
}
public var debugDescription: String {
return "\(items())"
}
}
extension Options {
func query(ignoringAttributeSynchronizable: Bool = true) -> [String: Any] {
var query = [String: Any]()
query[Class] = itemClass.rawValue
if let accessGroup = self.accessGroup {
query[AttributeAccessGroup] = accessGroup
}
if ignoringAttributeSynchronizable {
query[AttributeSynchronizable] = SynchronizableAny
} else {
query[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
}
switch itemClass {
case .genericPassword:
query[AttributeService] = service
case .internetPassword:
query[AttributeServer] = server.host
query[AttributePort] = server.port
query[AttributeProtocol] = protocolType.rawValue
query[AttributeAuthenticationType] = authenticationType.rawValue
}
if #available(OSX 10.10, *) {
if authenticationPrompt != nil {
query[UseOperationPrompt] = authenticationPrompt
}
}
#if !os(watchOS)
if #available(iOS 9.0, OSX 10.11, *) {
if authenticationContext != nil {
query[UseAuthenticationContext] = authenticationContext
}
}
#endif
return query
}
func attributes(key: String?, value: Data) -> ([String: Any], Error?) {
var attributes: [String: Any]
if key != nil {
attributes = query()
attributes[AttributeAccount] = key
} else {
attributes = [String: Any]()
}
attributes[ValueData] = value
if label != nil {
attributes[AttributeLabel] = label
}
if comment != nil {
attributes[AttributeComment] = comment
}
if let policy = authenticationPolicy {
if #available(OSX 10.10, *) {
var error: Unmanaged?
guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue as CFTypeRef, SecAccessControlCreateFlags(rawValue: CFOptionFlags(policy.rawValue)), &error) else {
if let error = error?.takeUnretainedValue() {
return (attributes, error.error)
}
return (attributes, Status.unexpectedError)
}
attributes[AttributeAccessControl] = accessControl
} else {
print("Unavailable 'Touch ID integration' on OS X versions prior to 10.10.")
}
} else {
attributes[AttributeAccessible] = accessibility.rawValue
}
attributes[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
return (attributes, nil)
}
}
// MARK:
extension Attributes: CustomStringConvertible, CustomDebugStringConvertible {
public var description: String {
return "\(attributes)"
}
public var debugDescription: String {
return description
}
}
extension ItemClass: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
switch rawValue {
case String(kSecClassGenericPassword):
self = .genericPassword
case String(kSecClassInternetPassword):
self = .internetPassword
default:
return nil
}
}
public var rawValue: String {
switch self {
case .genericPassword:
return String(kSecClassGenericPassword)
case .internetPassword:
return String(kSecClassInternetPassword)
}
}
public var description: String {
switch self {
case .genericPassword:
return "GenericPassword"
case .internetPassword:
return "InternetPassword"
}
}
}
extension ProtocolType: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
switch rawValue {
case String(kSecAttrProtocolFTP):
self = .ftp
case String(kSecAttrProtocolFTPAccount):
self = .ftpAccount
case String(kSecAttrProtocolHTTP):
self = .http
case String(kSecAttrProtocolIRC):
self = .irc
case String(kSecAttrProtocolNNTP):
self = .nntp
case String(kSecAttrProtocolPOP3):
self = .pop3
case String(kSecAttrProtocolSMTP):
self = .smtp
case String(kSecAttrProtocolSOCKS):
self = .socks
case String(kSecAttrProtocolIMAP):
self = .imap
case String(kSecAttrProtocolLDAP):
self = .ldap
case String(kSecAttrProtocolAppleTalk):
self = .appleTalk
case String(kSecAttrProtocolAFP):
self = .afp
case String(kSecAttrProtocolTelnet):
self = .telnet
case String(kSecAttrProtocolSSH):
self = .ssh
case String(kSecAttrProtocolFTPS):
self = .ftps
case String(kSecAttrProtocolHTTPS):
self = .https
case String(kSecAttrProtocolHTTPProxy):
self = .httpProxy
case String(kSecAttrProtocolHTTPSProxy):
self = .httpsProxy
case String(kSecAttrProtocolFTPProxy):
self = .ftpProxy
case String(kSecAttrProtocolSMB):
self = .smb
case String(kSecAttrProtocolRTSP):
self = .rtsp
case String(kSecAttrProtocolRTSPProxy):
self = .rtspProxy
case String(kSecAttrProtocolDAAP):
self = .daap
case String(kSecAttrProtocolEPPC):
self = .eppc
case String(kSecAttrProtocolIPP):
self = .ipp
case String(kSecAttrProtocolNNTPS):
self = .nntps
case String(kSecAttrProtocolLDAPS):
self = .ldaps
case String(kSecAttrProtocolTelnetS):
self = .telnetS
case String(kSecAttrProtocolIMAPS):
self = .imaps
case String(kSecAttrProtocolIRCS):
self = .ircs
case String(kSecAttrProtocolPOP3S):
self = .pop3S
default:
return nil
}
}
public var rawValue: String {
switch self {
case .ftp:
return String(kSecAttrProtocolFTP)
case .ftpAccount:
return String(kSecAttrProtocolFTPAccount)
case .http:
return String(kSecAttrProtocolHTTP)
case .irc:
return String(kSecAttrProtocolIRC)
case .nntp:
return String(kSecAttrProtocolNNTP)
case .pop3:
return String(kSecAttrProtocolPOP3)
case .smtp:
return String(kSecAttrProtocolSMTP)
case .socks:
return String(kSecAttrProtocolSOCKS)
case .imap:
return String(kSecAttrProtocolIMAP)
case .ldap:
return String(kSecAttrProtocolLDAP)
case .appleTalk:
return String(kSecAttrProtocolAppleTalk)
case .afp:
return String(kSecAttrProtocolAFP)
case .telnet:
return String(kSecAttrProtocolTelnet)
case .ssh:
return String(kSecAttrProtocolSSH)
case .ftps:
return String(kSecAttrProtocolFTPS)
case .https:
return String(kSecAttrProtocolHTTPS)
case .httpProxy:
return String(kSecAttrProtocolHTTPProxy)
case .httpsProxy:
return String(kSecAttrProtocolHTTPSProxy)
case .ftpProxy:
return String(kSecAttrProtocolFTPProxy)
case .smb:
return String(kSecAttrProtocolSMB)
case .rtsp:
return String(kSecAttrProtocolRTSP)
case .rtspProxy:
return String(kSecAttrProtocolRTSPProxy)
case .daap:
return String(kSecAttrProtocolDAAP)
case .eppc:
return String(kSecAttrProtocolEPPC)
case .ipp:
return String(kSecAttrProtocolIPP)
case .nntps:
return String(kSecAttrProtocolNNTPS)
case .ldaps:
return String(kSecAttrProtocolLDAPS)
case .telnetS:
return String(kSecAttrProtocolTelnetS)
case .imaps:
return String(kSecAttrProtocolIMAPS)
case .ircs:
return String(kSecAttrProtocolIRCS)
case .pop3S:
return String(kSecAttrProtocolPOP3S)
}
}
public var description: String {
switch self {
case .ftp:
return "FTP"
case .ftpAccount:
return "FTPAccount"
case .http:
return "HTTP"
case .irc:
return "IRC"
case .nntp:
return "NNTP"
case .pop3:
return "POP3"
case .smtp:
return "SMTP"
case .socks:
return "SOCKS"
case .imap:
return "IMAP"
case .ldap:
return "LDAP"
case .appleTalk:
return "AppleTalk"
case .afp:
return "AFP"
case .telnet:
return "Telnet"
case .ssh:
return "SSH"
case .ftps:
return "FTPS"
case .https:
return "HTTPS"
case .httpProxy:
return "HTTPProxy"
case .httpsProxy:
return "HTTPSProxy"
case .ftpProxy:
return "FTPProxy"
case .smb:
return "SMB"
case .rtsp:
return "RTSP"
case .rtspProxy:
return "RTSPProxy"
case .daap:
return "DAAP"
case .eppc:
return "EPPC"
case .ipp:
return "IPP"
case .nntps:
return "NNTPS"
case .ldaps:
return "LDAPS"
case .telnetS:
return "TelnetS"
case .imaps:
return "IMAPS"
case .ircs:
return "IRCS"
case .pop3S:
return "POP3S"
}
}
}
extension AuthenticationType: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
switch rawValue {
case String(kSecAttrAuthenticationTypeNTLM):
self = .ntlm
case String(kSecAttrAuthenticationTypeMSN):
self = .msn
case String(kSecAttrAuthenticationTypeDPA):
self = .dpa
case String(kSecAttrAuthenticationTypeRPA):
self = .rpa
case String(kSecAttrAuthenticationTypeHTTPBasic):
self = .httpBasic
case String(kSecAttrAuthenticationTypeHTTPDigest):
self = .httpDigest
case String(kSecAttrAuthenticationTypeHTMLForm):
self = .htmlForm
case String(kSecAttrAuthenticationTypeDefault):
self = .`default`
default:
return nil
}
}
public var rawValue: String {
switch self {
case .ntlm:
return String(kSecAttrAuthenticationTypeNTLM)
case .msn:
return String(kSecAttrAuthenticationTypeMSN)
case .dpa:
return String(kSecAttrAuthenticationTypeDPA)
case .rpa:
return String(kSecAttrAuthenticationTypeRPA)
case .httpBasic:
return String(kSecAttrAuthenticationTypeHTTPBasic)
case .httpDigest:
return String(kSecAttrAuthenticationTypeHTTPDigest)
case .htmlForm:
return String(kSecAttrAuthenticationTypeHTMLForm)
case .`default`:
return String(kSecAttrAuthenticationTypeDefault)
}
}
public var description: String {
switch self {
case .ntlm:
return "NTLM"
case .msn:
return "MSN"
case .dpa:
return "DPA"
case .rpa:
return "RPA"
case .httpBasic:
return "HTTPBasic"
case .httpDigest:
return "HTTPDigest"
case .htmlForm:
return "HTMLForm"
case .`default`:
return "Default"
}
}
}
extension Accessibility: RawRepresentable, CustomStringConvertible {
public init?(rawValue: String) {
if #available(OSX 10.10, *) {
switch rawValue {
case String(kSecAttrAccessibleWhenUnlocked):
self = .whenUnlocked
case String(kSecAttrAccessibleAfterFirstUnlock):
self = .afterFirstUnlock
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlways):
self = .always
#endif
case String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly):
self = .whenPasscodeSetThisDeviceOnly
case String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly):
self = .whenUnlockedThisDeviceOnly
case String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly):
self = .afterFirstUnlockThisDeviceOnly
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlwaysThisDeviceOnly):
self = .alwaysThisDeviceOnly
#endif
default:
return nil
}
} else {
switch rawValue {
case String(kSecAttrAccessibleWhenUnlocked):
self = .whenUnlocked
case String(kSecAttrAccessibleAfterFirstUnlock):
self = .afterFirstUnlock
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlways):
self = .always
#endif
case String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly):
self = .whenUnlockedThisDeviceOnly
case String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly):
self = .afterFirstUnlockThisDeviceOnly
#if !targetEnvironment(macCatalyst)
case String(kSecAttrAccessibleAlwaysThisDeviceOnly):
self = .alwaysThisDeviceOnly
#endif
default:
return nil
}
}
}
public var rawValue: String {
switch self {
case .whenUnlocked:
return String(kSecAttrAccessibleWhenUnlocked)
case .afterFirstUnlock:
return String(kSecAttrAccessibleAfterFirstUnlock)
#if !targetEnvironment(macCatalyst)
case .always:
return String(kSecAttrAccessibleAlways)
#endif
case .whenPasscodeSetThisDeviceOnly:
if #available(OSX 10.10, *) {
return String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)
} else {
fatalError("'Accessibility.WhenPasscodeSetThisDeviceOnly' is not available on this version of OS.")
}
case .whenUnlockedThisDeviceOnly:
return String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
case .afterFirstUnlockThisDeviceOnly:
return String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
#if !targetEnvironment(macCatalyst)
case .alwaysThisDeviceOnly:
return String(kSecAttrAccessibleAlwaysThisDeviceOnly)
#endif
}
}
public var description: String {
switch self {
case .whenUnlocked:
return "WhenUnlocked"
case .afterFirstUnlock:
return "AfterFirstUnlock"
#if !targetEnvironment(macCatalyst)
case .always:
return "Always"
#endif
case .whenPasscodeSetThisDeviceOnly:
return "WhenPasscodeSetThisDeviceOnly"
case .whenUnlockedThisDeviceOnly:
return "WhenUnlockedThisDeviceOnly"
case .afterFirstUnlockThisDeviceOnly:
return "AfterFirstUnlockThisDeviceOnly"
#if !targetEnvironment(macCatalyst)
case .alwaysThisDeviceOnly:
return "AlwaysThisDeviceOnly"
#endif
}
}
}
extension CFError {
var error: NSError {
let domain = CFErrorGetDomain(self) as String
let code = CFErrorGetCode(self)
let userInfo = CFErrorCopyUserInfo(self) as! [String: Any]
return NSError(domain: domain, code: code, userInfo: userInfo)
}
}
public enum Status: OSStatus, Error {
case success = 0
case unimplemented = -4
case diskFull = -34
case io = -36
case opWr = -49
case param = -50
case wrPerm = -61
case allocate = -108
case userCanceled = -128
case badReq = -909
case internalComponent = -2070
case notAvailable = -25291
case readOnly = -25292
case authFailed = -25293
case noSuchKeychain = -25294
case invalidKeychain = -25295
case duplicateKeychain = -25296
case duplicateCallback = -25297
case invalidCallback = -25298
case duplicateItem = -25299
case itemNotFound = -25300
case bufferTooSmall = -25301
case dataTooLarge = -25302
case noSuchAttr = -25303
case invalidItemRef = -25304
case invalidSearchRef = -25305
case noSuchClass = -25306
case noDefaultKeychain = -25307
case interactionNotAllowed = -25308
case readOnlyAttr = -25309
case wrongSecVersion = -25310
case keySizeNotAllowed = -25311
case noStorageModule = -25312
case noCertificateModule = -25313
case noPolicyModule = -25314
case interactionRequired = -25315
case dataNotAvailable = -25316
case dataNotModifiable = -25317
case createChainFailed = -25318
case invalidPrefsDomain = -25319
case inDarkWake = -25320
case aclNotSimple = -25240
case policyNotFound = -25241
case invalidTrustSetting = -25242
case noAccessForItem = -25243
case invalidOwnerEdit = -25244
case trustNotAvailable = -25245
case unsupportedFormat = -25256
case unknownFormat = -25257
case keyIsSensitive = -25258
case multiplePrivKeys = -25259
case passphraseRequired = -25260
case invalidPasswordRef = -25261
case invalidTrustSettings = -25262
case noTrustSettings = -25263
case pkcs12VerifyFailure = -25264
case invalidCertificate = -26265
case notSigner = -26267
case policyDenied = -26270
case invalidKey = -26274
case decode = -26275
case `internal` = -26276
case unsupportedAlgorithm = -26268
case unsupportedOperation = -26271
case unsupportedPadding = -26273
case itemInvalidKey = -34000
case itemInvalidKeyType = -34001
case itemInvalidValue = -34002
case itemClassMissing = -34003
case itemMatchUnsupported = -34004
case useItemListUnsupported = -34005
case useKeychainUnsupported = -34006
case useKeychainListUnsupported = -34007
case returnDataUnsupported = -34008
case returnAttributesUnsupported = -34009
case returnRefUnsupported = -34010
case returnPersitentRefUnsupported = -34011
case valueRefUnsupported = -34012
case valuePersistentRefUnsupported = -34013
case returnMissingPointer = -34014
case matchLimitUnsupported = -34015
case itemIllegalQuery = -34016
case waitForCallback = -34017
case missingEntitlement = -34018
case upgradePending = -34019
case mpSignatureInvalid = -25327
case otrTooOld = -25328
case otrIDTooNew = -25329
case serviceNotAvailable = -67585
case insufficientClientID = -67586
case deviceReset = -67587
case deviceFailed = -67588
case appleAddAppACLSubject = -67589
case applePublicKeyIncomplete = -67590
case appleSignatureMismatch = -67591
case appleInvalidKeyStartDate = -67592
case appleInvalidKeyEndDate = -67593
case conversionError = -67594
case appleSSLv2Rollback = -67595
case quotaExceeded = -67596
case fileTooBig = -67597
case invalidDatabaseBlob = -67598
case invalidKeyBlob = -67599
case incompatibleDatabaseBlob = -67600
case incompatibleKeyBlob = -67601
case hostNameMismatch = -67602
case unknownCriticalExtensionFlag = -67603
case noBasicConstraints = -67604
case noBasicConstraintsCA = -67605
case invalidAuthorityKeyID = -67606
case invalidSubjectKeyID = -67607
case invalidKeyUsageForPolicy = -67608
case invalidExtendedKeyUsage = -67609
case invalidIDLinkage = -67610
case pathLengthConstraintExceeded = -67611
case invalidRoot = -67612
case crlExpired = -67613
case crlNotValidYet = -67614
case crlNotFound = -67615
case crlServerDown = -67616
case crlBadURI = -67617
case unknownCertExtension = -67618
case unknownCRLExtension = -67619
case crlNotTrusted = -67620
case crlPolicyFailed = -67621
case idpFailure = -67622
case smimeEmailAddressesNotFound = -67623
case smimeBadExtendedKeyUsage = -67624
case smimeBadKeyUsage = -67625
case smimeKeyUsageNotCritical = -67626
case smimeNoEmailAddress = -67627
case smimeSubjAltNameNotCritical = -67628
case sslBadExtendedKeyUsage = -67629
case ocspBadResponse = -67630
case ocspBadRequest = -67631
case ocspUnavailable = -67632
case ocspStatusUnrecognized = -67633
case endOfData = -67634
case incompleteCertRevocationCheck = -67635
case networkFailure = -67636
case ocspNotTrustedToAnchor = -67637
case recordModified = -67638
case ocspSignatureError = -67639
case ocspNoSigner = -67640
case ocspResponderMalformedReq = -67641
case ocspResponderInternalError = -67642
case ocspResponderTryLater = -67643
case ocspResponderSignatureRequired = -67644
case ocspResponderUnauthorized = -67645
case ocspResponseNonceMismatch = -67646
case codeSigningBadCertChainLength = -67647
case codeSigningNoBasicConstraints = -67648
case codeSigningBadPathLengthConstraint = -67649
case codeSigningNoExtendedKeyUsage = -67650
case codeSigningDevelopment = -67651
case resourceSignBadCertChainLength = -67652
case resourceSignBadExtKeyUsage = -67653
case trustSettingDeny = -67654
case invalidSubjectName = -67655
case unknownQualifiedCertStatement = -67656
case mobileMeRequestQueued = -67657
case mobileMeRequestRedirected = -67658
case mobileMeServerError = -67659
case mobileMeServerNotAvailable = -67660
case mobileMeServerAlreadyExists = -67661
case mobileMeServerServiceErr = -67662
case mobileMeRequestAlreadyPending = -67663
case mobileMeNoRequestPending = -67664
case mobileMeCSRVerifyFailure = -67665
case mobileMeFailedConsistencyCheck = -67666
case notInitialized = -67667
case invalidHandleUsage = -67668
case pvcReferentNotFound = -67669
case functionIntegrityFail = -67670
case internalError = -67671
case memoryError = -67672
case invalidData = -67673
case mdsError = -67674
case invalidPointer = -67675
case selfCheckFailed = -67676
case functionFailed = -67677
case moduleManifestVerifyFailed = -67678
case invalidGUID = -67679
case invalidHandle = -67680
case invalidDBList = -67681
case invalidPassthroughID = -67682
case invalidNetworkAddress = -67683
case crlAlreadySigned = -67684
case invalidNumberOfFields = -67685
case verificationFailure = -67686
case unknownTag = -67687
case invalidSignature = -67688
case invalidName = -67689
case invalidCertificateRef = -67690
case invalidCertificateGroup = -67691
case tagNotFound = -67692
case invalidQuery = -67693
case invalidValue = -67694
case callbackFailed = -67695
case aclDeleteFailed = -67696
case aclReplaceFailed = -67697
case aclAddFailed = -67698
case aclChangeFailed = -67699
case invalidAccessCredentials = -67700
case invalidRecord = -67701
case invalidACL = -67702
case invalidSampleValue = -67703
case incompatibleVersion = -67704
case privilegeNotGranted = -67705
case invalidScope = -67706
case pvcAlreadyConfigured = -67707
case invalidPVC = -67708
case emmLoadFailed = -67709
case emmUnloadFailed = -67710
case addinLoadFailed = -67711
case invalidKeyRef = -67712
case invalidKeyHierarchy = -67713
case addinUnloadFailed = -67714
case libraryReferenceNotFound = -67715
case invalidAddinFunctionTable = -67716
case invalidServiceMask = -67717
case moduleNotLoaded = -67718
case invalidSubServiceID = -67719
case attributeNotInContext = -67720
case moduleManagerInitializeFailed = -67721
case moduleManagerNotFound = -67722
case eventNotificationCallbackNotFound = -67723
case inputLengthError = -67724
case outputLengthError = -67725
case privilegeNotSupported = -67726
case deviceError = -67727
case attachHandleBusy = -67728
case notLoggedIn = -67729
case algorithmMismatch = -67730
case keyUsageIncorrect = -67731
case keyBlobTypeIncorrect = -67732
case keyHeaderInconsistent = -67733
case unsupportedKeyFormat = -67734
case unsupportedKeySize = -67735
case invalidKeyUsageMask = -67736
case unsupportedKeyUsageMask = -67737
case invalidKeyAttributeMask = -67738
case unsupportedKeyAttributeMask = -67739
case invalidKeyLabel = -67740
case unsupportedKeyLabel = -67741
case invalidKeyFormat = -67742
case unsupportedVectorOfBuffers = -67743
case invalidInputVector = -67744
case invalidOutputVector = -67745
case invalidContext = -67746
case invalidAlgorithm = -67747
case invalidAttributeKey = -67748
case missingAttributeKey = -67749
case invalidAttributeInitVector = -67750
case missingAttributeInitVector = -67751
case invalidAttributeSalt = -67752
case missingAttributeSalt = -67753
case invalidAttributePadding = -67754
case missingAttributePadding = -67755
case invalidAttributeRandom = -67756
case missingAttributeRandom = -67757
case invalidAttributeSeed = -67758
case missingAttributeSeed = -67759
case invalidAttributePassphrase = -67760
case missingAttributePassphrase = -67761
case invalidAttributeKeyLength = -67762
case missingAttributeKeyLength = -67763
case invalidAttributeBlockSize = -67764
case missingAttributeBlockSize = -67765
case invalidAttributeOutputSize = -67766
case missingAttributeOutputSize = -67767
case invalidAttributeRounds = -67768
case missingAttributeRounds = -67769
case invalidAlgorithmParms = -67770
case missingAlgorithmParms = -67771
case invalidAttributeLabel = -67772
case missingAttributeLabel = -67773
case invalidAttributeKeyType = -67774
case missingAttributeKeyType = -67775
case invalidAttributeMode = -67776
case missingAttributeMode = -67777
case invalidAttributeEffectiveBits = -67778
case missingAttributeEffectiveBits = -67779
case invalidAttributeStartDate = -67780
case missingAttributeStartDate = -67781
case invalidAttributeEndDate = -67782
case missingAttributeEndDate = -67783
case invalidAttributeVersion = -67784
case missingAttributeVersion = -67785
case invalidAttributePrime = -67786
case missingAttributePrime = -67787
case invalidAttributeBase = -67788
case missingAttributeBase = -67789
case invalidAttributeSubprime = -67790
case missingAttributeSubprime = -67791
case invalidAttributeIterationCount = -67792
case missingAttributeIterationCount = -67793
case invalidAttributeDLDBHandle = -67794
case missingAttributeDLDBHandle = -67795
case invalidAttributeAccessCredentials = -67796
case missingAttributeAccessCredentials = -67797
case invalidAttributePublicKeyFormat = -67798
case missingAttributePublicKeyFormat = -67799
case invalidAttributePrivateKeyFormat = -67800
case missingAttributePrivateKeyFormat = -67801
case invalidAttributeSymmetricKeyFormat = -67802
case missingAttributeSymmetricKeyFormat = -67803
case invalidAttributeWrappedKeyFormat = -67804
case missingAttributeWrappedKeyFormat = -67805
case stagedOperationInProgress = -67806
case stagedOperationNotStarted = -67807
case verifyFailed = -67808
case querySizeUnknown = -67809
case blockSizeMismatch = -67810
case publicKeyInconsistent = -67811
case deviceVerifyFailed = -67812
case invalidLoginName = -67813
case alreadyLoggedIn = -67814
case invalidDigestAlgorithm = -67815
case invalidCRLGroup = -67816
case certificateCannotOperate = -67817
case certificateExpired = -67818
case certificateNotValidYet = -67819
case certificateRevoked = -67820
case certificateSuspended = -67821
case insufficientCredentials = -67822
case invalidAction = -67823
case invalidAuthority = -67824
case verifyActionFailed = -67825
case invalidCertAuthority = -67826
case invaldCRLAuthority = -67827
case invalidCRLEncoding = -67828
case invalidCRLType = -67829
case invalidCRL = -67830
case invalidFormType = -67831
case invalidID = -67832
case invalidIdentifier = -67833
case invalidIndex = -67834
case invalidPolicyIdentifiers = -67835
case invalidTimeString = -67836
case invalidReason = -67837
case invalidRequestInputs = -67838
case invalidResponseVector = -67839
case invalidStopOnPolicy = -67840
case invalidTuple = -67841
case multipleValuesUnsupported = -67842
case notTrusted = -67843
case noDefaultAuthority = -67844
case rejectedForm = -67845
case requestLost = -67846
case requestRejected = -67847
case unsupportedAddressType = -67848
case unsupportedService = -67849
case invalidTupleGroup = -67850
case invalidBaseACLs = -67851
case invalidTupleCredendtials = -67852
case invalidEncoding = -67853
case invalidValidityPeriod = -67854
case invalidRequestor = -67855
case requestDescriptor = -67856
case invalidBundleInfo = -67857
case invalidCRLIndex = -67858
case noFieldValues = -67859
case unsupportedFieldFormat = -67860
case unsupportedIndexInfo = -67861
case unsupportedLocality = -67862
case unsupportedNumAttributes = -67863
case unsupportedNumIndexes = -67864
case unsupportedNumRecordTypes = -67865
case fieldSpecifiedMultiple = -67866
case incompatibleFieldFormat = -67867
case invalidParsingModule = -67868
case databaseLocked = -67869
case datastoreIsOpen = -67870
case missingValue = -67871
case unsupportedQueryLimits = -67872
case unsupportedNumSelectionPreds = -67873
case unsupportedOperator = -67874
case invalidDBLocation = -67875
case invalidAccessRequest = -67876
case invalidIndexInfo = -67877
case invalidNewOwner = -67878
case invalidModifyMode = -67879
case missingRequiredExtension = -67880
case extendedKeyUsageNotCritical = -67881
case timestampMissing = -67882
case timestampInvalid = -67883
case timestampNotTrusted = -67884
case timestampServiceNotAvailable = -67885
case timestampBadAlg = -67886
case timestampBadRequest = -67887
case timestampBadDataFormat = -67888
case timestampTimeNotAvailable = -67889
case timestampUnacceptedPolicy = -67890
case timestampUnacceptedExtension = -67891
case timestampAddInfoNotAvailable = -67892
case timestampSystemFailure = -67893
case signingTimeMissing = -67894
case timestampRejection = -67895
case timestampWaiting = -67896
case timestampRevocationWarning = -67897
case timestampRevocationNotification = -67898
case unexpectedError = -99999
}
extension Status: RawRepresentable, CustomStringConvertible {
public init(status: OSStatus) {
if let mappedStatus = Status(rawValue: status) {
self = mappedStatus
} else {
self = .unexpectedError
}
}
public var description: String {
switch self {
case .success:
return "No error."
case .unimplemented:
return "Function or operation not implemented."
case .diskFull:
return "The disk is full."
case .io:
return "I/O error (bummers)"
case .opWr:
return "file already open with with write permission"
case .param:
return "One or more parameters passed to a function were not valid."
case .wrPerm:
return "write permissions error"
case .allocate:
return "Failed to allocate memory."
case .userCanceled:
return "User canceled the operation."
case .badReq:
return "Bad parameter or invalid state for operation."
case .internalComponent:
return ""
case .notAvailable:
return "No keychain is available. You may need to restart your computer."
case .readOnly:
return "This keychain cannot be modified."
case .authFailed:
return "The user name or passphrase you entered is not correct."
case .noSuchKeychain:
return "The specified keychain could not be found."
case .invalidKeychain:
return "The specified keychain is not a valid keychain file."
case .duplicateKeychain:
return "A keychain with the same name already exists."
case .duplicateCallback:
return "The specified callback function is already installed."
case .invalidCallback:
return "The specified callback function is not valid."
case .duplicateItem:
return "The specified item already exists in the keychain."
case .itemNotFound:
return "The specified item could not be found in the keychain."
case .bufferTooSmall:
return "There is not enough memory available to use the specified item."
case .dataTooLarge:
return "This item contains information which is too large or in a format that cannot be displayed."
case .noSuchAttr:
return "The specified attribute does not exist."
case .invalidItemRef:
return "The specified item is no longer valid. It may have been deleted from the keychain."
case .invalidSearchRef:
return "Unable to search the current keychain."
case .noSuchClass:
return "The specified item does not appear to be a valid keychain item."
case .noDefaultKeychain:
return "A default keychain could not be found."
case .interactionNotAllowed:
return "User interaction is not allowed."
case .readOnlyAttr:
return "The specified attribute could not be modified."
case .wrongSecVersion:
return "This keychain was created by a different version of the system software and cannot be opened."
case .keySizeNotAllowed:
return "This item specifies a key size which is too large."
case .noStorageModule:
return "A required component (data storage module) could not be loaded. You may need to restart your computer."
case .noCertificateModule:
return "A required component (certificate module) could not be loaded. You may need to restart your computer."
case .noPolicyModule:
return "A required component (policy module) could not be loaded. You may need to restart your computer."
case .interactionRequired:
return "User interaction is required, but is currently not allowed."
case .dataNotAvailable:
return "The contents of this item cannot be retrieved."
case .dataNotModifiable:
return "The contents of this item cannot be modified."
case .createChainFailed:
return "One or more certificates required to validate this certificate cannot be found."
case .invalidPrefsDomain:
return "The specified preferences domain is not valid."
case .inDarkWake:
return "In dark wake, no UI possible"
case .aclNotSimple:
return "The specified access control list is not in standard (simple) form."
case .policyNotFound:
return "The specified policy cannot be found."
case .invalidTrustSetting:
return "The specified trust setting is invalid."
case .noAccessForItem:
return "The specified item has no access control."
case .invalidOwnerEdit:
return "Invalid attempt to change the owner of this item."
case .trustNotAvailable:
return "No trust results are available."
case .unsupportedFormat:
return "Import/Export format unsupported."
case .unknownFormat:
return "Unknown format in import."
case .keyIsSensitive:
return "Key material must be wrapped for export."
case .multiplePrivKeys:
return "An attempt was made to import multiple private keys."
case .passphraseRequired:
return "Passphrase is required for import/export."
case .invalidPasswordRef:
return "The password reference was invalid."
case .invalidTrustSettings:
return "The Trust Settings Record was corrupted."
case .noTrustSettings:
return "No Trust Settings were found."
case .pkcs12VerifyFailure:
return "MAC verification failed during PKCS12 import (wrong password?)"
case .invalidCertificate:
return "This certificate could not be decoded."
case .notSigner:
return "A certificate was not signed by its proposed parent."
case .policyDenied:
return "The certificate chain was not trusted due to a policy not accepting it."
case .invalidKey:
return "The provided key material was not valid."
case .decode:
return "Unable to decode the provided data."
case .`internal`:
return "An internal error occurred in the Security framework."
case .unsupportedAlgorithm:
return "An unsupported algorithm was encountered."
case .unsupportedOperation:
return "The operation you requested is not supported by this key."
case .unsupportedPadding:
return "The padding you requested is not supported."
case .itemInvalidKey:
return "A string key in dictionary is not one of the supported keys."
case .itemInvalidKeyType:
return "A key in a dictionary is neither a CFStringRef nor a CFNumberRef."
case .itemInvalidValue:
return "A value in a dictionary is an invalid (or unsupported) CF type."
case .itemClassMissing:
return "No kSecItemClass key was specified in a dictionary."
case .itemMatchUnsupported:
return "The caller passed one or more kSecMatch keys to a function which does not support matches."
case .useItemListUnsupported:
return "The caller passed in a kSecUseItemList key to a function which does not support it."
case .useKeychainUnsupported:
return "The caller passed in a kSecUseKeychain key to a function which does not support it."
case .useKeychainListUnsupported:
return "The caller passed in a kSecUseKeychainList key to a function which does not support it."
case .returnDataUnsupported:
return "The caller passed in a kSecReturnData key to a function which does not support it."
case .returnAttributesUnsupported:
return "The caller passed in a kSecReturnAttributes key to a function which does not support it."
case .returnRefUnsupported:
return "The caller passed in a kSecReturnRef key to a function which does not support it."
case .returnPersitentRefUnsupported:
return "The caller passed in a kSecReturnPersistentRef key to a function which does not support it."
case .valueRefUnsupported:
return "The caller passed in a kSecValueRef key to a function which does not support it."
case .valuePersistentRefUnsupported:
return "The caller passed in a kSecValuePersistentRef key to a function which does not support it."
case .returnMissingPointer:
return "The caller passed asked for something to be returned but did not pass in a result pointer."
case .matchLimitUnsupported:
return "The caller passed in a kSecMatchLimit key to a call which does not support limits."
case .itemIllegalQuery:
return "The caller passed in a query which contained too many keys."
case .waitForCallback:
return "This operation is incomplete, until the callback is invoked (not an error)."
case .missingEntitlement:
return "Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements."
case .upgradePending:
return "Error returned if keychain database needs a schema migration but the device is locked, clients should wait for a device unlock notification and retry the command."
case .mpSignatureInvalid:
return "Signature invalid on MP message"
case .otrTooOld:
return "Message is too old to use"
case .otrIDTooNew:
return "Key ID is too new to use! Message from the future?"
case .serviceNotAvailable:
return "The required service is not available."
case .insufficientClientID:
return "The client ID is not correct."
case .deviceReset:
return "A device reset has occurred."
case .deviceFailed:
return "A device failure has occurred."
case .appleAddAppACLSubject:
return "Adding an application ACL subject failed."
case .applePublicKeyIncomplete:
return "The public key is incomplete."
case .appleSignatureMismatch:
return "A signature mismatch has occurred."
case .appleInvalidKeyStartDate:
return "The specified key has an invalid start date."
case .appleInvalidKeyEndDate:
return "The specified key has an invalid end date."
case .conversionError:
return "A conversion error has occurred."
case .appleSSLv2Rollback:
return "A SSLv2 rollback error has occurred."
case .quotaExceeded:
return "The quota was exceeded."
case .fileTooBig:
return "The file is too big."
case .invalidDatabaseBlob:
return "The specified database has an invalid blob."
case .invalidKeyBlob:
return "The specified database has an invalid key blob."
case .incompatibleDatabaseBlob:
return "The specified database has an incompatible blob."
case .incompatibleKeyBlob:
return "The specified database has an incompatible key blob."
case .hostNameMismatch:
return "A host name mismatch has occurred."
case .unknownCriticalExtensionFlag:
return "There is an unknown critical extension flag."
case .noBasicConstraints:
return "No basic constraints were found."
case .noBasicConstraintsCA:
return "No basic CA constraints were found."
case .invalidAuthorityKeyID:
return "The authority key ID is not valid."
case .invalidSubjectKeyID:
return "The subject key ID is not valid."
case .invalidKeyUsageForPolicy:
return "The key usage is not valid for the specified policy."
case .invalidExtendedKeyUsage:
return "The extended key usage is not valid."
case .invalidIDLinkage:
return "The ID linkage is not valid."
case .pathLengthConstraintExceeded:
return "The path length constraint was exceeded."
case .invalidRoot:
return "The root or anchor certificate is not valid."
case .crlExpired:
return "The CRL has expired."
case .crlNotValidYet:
return "The CRL is not yet valid."
case .crlNotFound:
return "The CRL was not found."
case .crlServerDown:
return "The CRL server is down."
case .crlBadURI:
return "The CRL has a bad Uniform Resource Identifier."
case .unknownCertExtension:
return "An unknown certificate extension was encountered."
case .unknownCRLExtension:
return "An unknown CRL extension was encountered."
case .crlNotTrusted:
return "The CRL is not trusted."
case .crlPolicyFailed:
return "The CRL policy failed."
case .idpFailure:
return "The issuing distribution point was not valid."
case .smimeEmailAddressesNotFound:
return "An email address mismatch was encountered."
case .smimeBadExtendedKeyUsage:
return "The appropriate extended key usage for SMIME was not found."
case .smimeBadKeyUsage:
return "The key usage is not compatible with SMIME."
case .smimeKeyUsageNotCritical:
return "The key usage extension is not marked as critical."
case .smimeNoEmailAddress:
return "No email address was found in the certificate."
case .smimeSubjAltNameNotCritical:
return "The subject alternative name extension is not marked as critical."
case .sslBadExtendedKeyUsage:
return "The appropriate extended key usage for SSL was not found."
case .ocspBadResponse:
return "The OCSP response was incorrect or could not be parsed."
case .ocspBadRequest:
return "The OCSP request was incorrect or could not be parsed."
case .ocspUnavailable:
return "OCSP service is unavailable."
case .ocspStatusUnrecognized:
return "The OCSP server did not recognize this certificate."
case .endOfData:
return "An end-of-data was detected."
case .incompleteCertRevocationCheck:
return "An incomplete certificate revocation check occurred."
case .networkFailure:
return "A network failure occurred."
case .ocspNotTrustedToAnchor:
return "The OCSP response was not trusted to a root or anchor certificate."
case .recordModified:
return "The record was modified."
case .ocspSignatureError:
return "The OCSP response had an invalid signature."
case .ocspNoSigner:
return "The OCSP response had no signer."
case .ocspResponderMalformedReq:
return "The OCSP responder was given a malformed request."
case .ocspResponderInternalError:
return "The OCSP responder encountered an internal error."
case .ocspResponderTryLater:
return "The OCSP responder is busy, try again later."
case .ocspResponderSignatureRequired:
return "The OCSP responder requires a signature."
case .ocspResponderUnauthorized:
return "The OCSP responder rejected this request as unauthorized."
case .ocspResponseNonceMismatch:
return "The OCSP response nonce did not match the request."
case .codeSigningBadCertChainLength:
return "Code signing encountered an incorrect certificate chain length."
case .codeSigningNoBasicConstraints:
return "Code signing found no basic constraints."
case .codeSigningBadPathLengthConstraint:
return "Code signing encountered an incorrect path length constraint."
case .codeSigningNoExtendedKeyUsage:
return "Code signing found no extended key usage."
case .codeSigningDevelopment:
return "Code signing indicated use of a development-only certificate."
case .resourceSignBadCertChainLength:
return "Resource signing has encountered an incorrect certificate chain length."
case .resourceSignBadExtKeyUsage:
return "Resource signing has encountered an error in the extended key usage."
case .trustSettingDeny:
return "The trust setting for this policy was set to Deny."
case .invalidSubjectName:
return "An invalid certificate subject name was encountered."
case .unknownQualifiedCertStatement:
return "An unknown qualified certificate statement was encountered."
case .mobileMeRequestQueued:
return "The MobileMe request will be sent during the next connection."
case .mobileMeRequestRedirected:
return "The MobileMe request was redirected."
case .mobileMeServerError:
return "A MobileMe server error occurred."
case .mobileMeServerNotAvailable:
return "The MobileMe server is not available."
case .mobileMeServerAlreadyExists:
return "The MobileMe server reported that the item already exists."
case .mobileMeServerServiceErr:
return "A MobileMe service error has occurred."
case .mobileMeRequestAlreadyPending:
return "A MobileMe request is already pending."
case .mobileMeNoRequestPending:
return "MobileMe has no request pending."
case .mobileMeCSRVerifyFailure:
return "A MobileMe CSR verification failure has occurred."
case .mobileMeFailedConsistencyCheck:
return "MobileMe has found a failed consistency check."
case .notInitialized:
return "A function was called without initializing CSSM."
case .invalidHandleUsage:
return "The CSSM handle does not match with the service type."
case .pvcReferentNotFound:
return "A reference to the calling module was not found in the list of authorized callers."
case .functionIntegrityFail:
return "A function address was not within the verified module."
case .internalError:
return "An internal error has occurred."
case .memoryError:
return "A memory error has occurred."
case .invalidData:
return "Invalid data was encountered."
case .mdsError:
return "A Module Directory Service error has occurred."
case .invalidPointer:
return "An invalid pointer was encountered."
case .selfCheckFailed:
return "Self-check has failed."
case .functionFailed:
return "A function has failed."
case .moduleManifestVerifyFailed:
return "A module manifest verification failure has occurred."
case .invalidGUID:
return "An invalid GUID was encountered."
case .invalidHandle:
return "An invalid handle was encountered."
case .invalidDBList:
return "An invalid DB list was encountered."
case .invalidPassthroughID:
return "An invalid passthrough ID was encountered."
case .invalidNetworkAddress:
return "An invalid network address was encountered."
case .crlAlreadySigned:
return "The certificate revocation list is already signed."
case .invalidNumberOfFields:
return "An invalid number of fields were encountered."
case .verificationFailure:
return "A verification failure occurred."
case .unknownTag:
return "An unknown tag was encountered."
case .invalidSignature:
return "An invalid signature was encountered."
case .invalidName:
return "An invalid name was encountered."
case .invalidCertificateRef:
return "An invalid certificate reference was encountered."
case .invalidCertificateGroup:
return "An invalid certificate group was encountered."
case .tagNotFound:
return "The specified tag was not found."
case .invalidQuery:
return "The specified query was not valid."
case .invalidValue:
return "An invalid value was detected."
case .callbackFailed:
return "A callback has failed."
case .aclDeleteFailed:
return "An ACL delete operation has failed."
case .aclReplaceFailed:
return "An ACL replace operation has failed."
case .aclAddFailed:
return "An ACL add operation has failed."
case .aclChangeFailed:
return "An ACL change operation has failed."
case .invalidAccessCredentials:
return "Invalid access credentials were encountered."
case .invalidRecord:
return "An invalid record was encountered."
case .invalidACL:
return "An invalid ACL was encountered."
case .invalidSampleValue:
return "An invalid sample value was encountered."
case .incompatibleVersion:
return "An incompatible version was encountered."
case .privilegeNotGranted:
return "The privilege was not granted."
case .invalidScope:
return "An invalid scope was encountered."
case .pvcAlreadyConfigured:
return "The PVC is already configured."
case .invalidPVC:
return "An invalid PVC was encountered."
case .emmLoadFailed:
return "The EMM load has failed."
case .emmUnloadFailed:
return "The EMM unload has failed."
case .addinLoadFailed:
return "The add-in load operation has failed."
case .invalidKeyRef:
return "An invalid key was encountered."
case .invalidKeyHierarchy:
return "An invalid key hierarchy was encountered."
case .addinUnloadFailed:
return "The add-in unload operation has failed."
case .libraryReferenceNotFound:
return "A library reference was not found."
case .invalidAddinFunctionTable:
return "An invalid add-in function table was encountered."
case .invalidServiceMask:
return "An invalid service mask was encountered."
case .moduleNotLoaded:
return "A module was not loaded."
case .invalidSubServiceID:
return "An invalid subservice ID was encountered."
case .attributeNotInContext:
return "An attribute was not in the context."
case .moduleManagerInitializeFailed:
return "A module failed to initialize."
case .moduleManagerNotFound:
return "A module was not found."
case .eventNotificationCallbackNotFound:
return "An event notification callback was not found."
case .inputLengthError:
return "An input length error was encountered."
case .outputLengthError:
return "An output length error was encountered."
case .privilegeNotSupported:
return "The privilege is not supported."
case .deviceError:
return "A device error was encountered."
case .attachHandleBusy:
return "The CSP handle was busy."
case .notLoggedIn:
return "You are not logged in."
case .algorithmMismatch:
return "An algorithm mismatch was encountered."
case .keyUsageIncorrect:
return "The key usage is incorrect."
case .keyBlobTypeIncorrect:
return "The key blob type is incorrect."
case .keyHeaderInconsistent:
return "The key header is inconsistent."
case .unsupportedKeyFormat:
return "The key header format is not supported."
case .unsupportedKeySize:
return "The key size is not supported."
case .invalidKeyUsageMask:
return "The key usage mask is not valid."
case .unsupportedKeyUsageMask:
return "The key usage mask is not supported."
case .invalidKeyAttributeMask:
return "The key attribute mask is not valid."
case .unsupportedKeyAttributeMask:
return "The key attribute mask is not supported."
case .invalidKeyLabel:
return "The key label is not valid."
case .unsupportedKeyLabel:
return "The key label is not supported."
case .invalidKeyFormat:
return "The key format is not valid."
case .unsupportedVectorOfBuffers:
return "The vector of buffers is not supported."
case .invalidInputVector:
return "The input vector is not valid."
case .invalidOutputVector:
return "The output vector is not valid."
case .invalidContext:
return "An invalid context was encountered."
case .invalidAlgorithm:
return "An invalid algorithm was encountered."
case .invalidAttributeKey:
return "A key attribute was not valid."
case .missingAttributeKey:
return "A key attribute was missing."
case .invalidAttributeInitVector:
return "An init vector attribute was not valid."
case .missingAttributeInitVector:
return "An init vector attribute was missing."
case .invalidAttributeSalt:
return "A salt attribute was not valid."
case .missingAttributeSalt:
return "A salt attribute was missing."
case .invalidAttributePadding:
return "A padding attribute was not valid."
case .missingAttributePadding:
return "A padding attribute was missing."
case .invalidAttributeRandom:
return "A random number attribute was not valid."
case .missingAttributeRandom:
return "A random number attribute was missing."
case .invalidAttributeSeed:
return "A seed attribute was not valid."
case .missingAttributeSeed:
return "A seed attribute was missing."
case .invalidAttributePassphrase:
return "A passphrase attribute was not valid."
case .missingAttributePassphrase:
return "A passphrase attribute was missing."
case .invalidAttributeKeyLength:
return "A key length attribute was not valid."
case .missingAttributeKeyLength:
return "A key length attribute was missing."
case .invalidAttributeBlockSize:
return "A block size attribute was not valid."
case .missingAttributeBlockSize:
return "A block size attribute was missing."
case .invalidAttributeOutputSize:
return "An output size attribute was not valid."
case .missingAttributeOutputSize:
return "An output size attribute was missing."
case .invalidAttributeRounds:
return "The number of rounds attribute was not valid."
case .missingAttributeRounds:
return "The number of rounds attribute was missing."
case .invalidAlgorithmParms:
return "An algorithm parameters attribute was not valid."
case .missingAlgorithmParms:
return "An algorithm parameters attribute was missing."
case .invalidAttributeLabel:
return "A label attribute was not valid."
case .missingAttributeLabel:
return "A label attribute was missing."
case .invalidAttributeKeyType:
return "A key type attribute was not valid."
case .missingAttributeKeyType:
return "A key type attribute was missing."
case .invalidAttributeMode:
return "A mode attribute was not valid."
case .missingAttributeMode:
return "A mode attribute was missing."
case .invalidAttributeEffectiveBits:
return "An effective bits attribute was not valid."
case .missingAttributeEffectiveBits:
return "An effective bits attribute was missing."
case .invalidAttributeStartDate:
return "A start date attribute was not valid."
case .missingAttributeStartDate:
return "A start date attribute was missing."
case .invalidAttributeEndDate:
return "An end date attribute was not valid."
case .missingAttributeEndDate:
return "An end date attribute was missing."
case .invalidAttributeVersion:
return "A version attribute was not valid."
case .missingAttributeVersion:
return "A version attribute was missing."
case .invalidAttributePrime:
return "A prime attribute was not valid."
case .missingAttributePrime:
return "A prime attribute was missing."
case .invalidAttributeBase:
return "A base attribute was not valid."
case .missingAttributeBase:
return "A base attribute was missing."
case .invalidAttributeSubprime:
return "A subprime attribute was not valid."
case .missingAttributeSubprime:
return "A subprime attribute was missing."
case .invalidAttributeIterationCount:
return "An iteration count attribute was not valid."
case .missingAttributeIterationCount:
return "An iteration count attribute was missing."
case .invalidAttributeDLDBHandle:
return "A database handle attribute was not valid."
case .missingAttributeDLDBHandle:
return "A database handle attribute was missing."
case .invalidAttributeAccessCredentials:
return "An access credentials attribute was not valid."
case .missingAttributeAccessCredentials:
return "An access credentials attribute was missing."
case .invalidAttributePublicKeyFormat:
return "A public key format attribute was not valid."
case .missingAttributePublicKeyFormat:
return "A public key format attribute was missing."
case .invalidAttributePrivateKeyFormat:
return "A private key format attribute was not valid."
case .missingAttributePrivateKeyFormat:
return "A private key format attribute was missing."
case .invalidAttributeSymmetricKeyFormat:
return "A symmetric key format attribute was not valid."
case .missingAttributeSymmetricKeyFormat:
return "A symmetric key format attribute was missing."
case .invalidAttributeWrappedKeyFormat:
return "A wrapped key format attribute was not valid."
case .missingAttributeWrappedKeyFormat:
return "A wrapped key format attribute was missing."
case .stagedOperationInProgress:
return "A staged operation is in progress."
case .stagedOperationNotStarted:
return "A staged operation was not started."
case .verifyFailed:
return "A cryptographic verification failure has occurred."
case .querySizeUnknown:
return "The query size is unknown."
case .blockSizeMismatch:
return "A block size mismatch occurred."
case .publicKeyInconsistent:
return "The public key was inconsistent."
case .deviceVerifyFailed:
return "A device verification failure has occurred."
case .invalidLoginName:
return "An invalid login name was detected."
case .alreadyLoggedIn:
return "The user is already logged in."
case .invalidDigestAlgorithm:
return "An invalid digest algorithm was detected."
case .invalidCRLGroup:
return "An invalid CRL group was detected."
case .certificateCannotOperate:
return "The certificate cannot operate."
case .certificateExpired:
return "An expired certificate was detected."
case .certificateNotValidYet:
return "The certificate is not yet valid."
case .certificateRevoked:
return "The certificate was revoked."
case .certificateSuspended:
return "The certificate was suspended."
case .insufficientCredentials:
return "Insufficient credentials were detected."
case .invalidAction:
return "The action was not valid."
case .invalidAuthority:
return "The authority was not valid."
case .verifyActionFailed:
return "A verify action has failed."
case .invalidCertAuthority:
return "The certificate authority was not valid."
case .invaldCRLAuthority:
return "The CRL authority was not valid."
case .invalidCRLEncoding:
return "The CRL encoding was not valid."
case .invalidCRLType:
return "The CRL type was not valid."
case .invalidCRL:
return "The CRL was not valid."
case .invalidFormType:
return "The form type was not valid."
case .invalidID:
return "The ID was not valid."
case .invalidIdentifier:
return "The identifier was not valid."
case .invalidIndex:
return "The index was not valid."
case .invalidPolicyIdentifiers:
return "The policy identifiers are not valid."
case .invalidTimeString:
return "The time specified was not valid."
case .invalidReason:
return "The trust policy reason was not valid."
case .invalidRequestInputs:
return "The request inputs are not valid."
case .invalidResponseVector:
return "The response vector was not valid."
case .invalidStopOnPolicy:
return "The stop-on policy was not valid."
case .invalidTuple:
return "The tuple was not valid."
case .multipleValuesUnsupported:
return "Multiple values are not supported."
case .notTrusted:
return "The trust policy was not trusted."
case .noDefaultAuthority:
return "No default authority was detected."
case .rejectedForm:
return "The trust policy had a rejected form."
case .requestLost:
return "The request was lost."
case .requestRejected:
return "The request was rejected."
case .unsupportedAddressType:
return "The address type is not supported."
case .unsupportedService:
return "The service is not supported."
case .invalidTupleGroup:
return "The tuple group was not valid."
case .invalidBaseACLs:
return "The base ACLs are not valid."
case .invalidTupleCredendtials:
return "The tuple credentials are not valid."
case .invalidEncoding:
return "The encoding was not valid."
case .invalidValidityPeriod:
return "The validity period was not valid."
case .invalidRequestor:
return "The requestor was not valid."
case .requestDescriptor:
return "The request descriptor was not valid."
case .invalidBundleInfo:
return "The bundle information was not valid."
case .invalidCRLIndex:
return "The CRL index was not valid."
case .noFieldValues:
return "No field values were detected."
case .unsupportedFieldFormat:
return "The field format is not supported."
case .unsupportedIndexInfo:
return "The index information is not supported."
case .unsupportedLocality:
return "The locality is not supported."
case .unsupportedNumAttributes:
return "The number of attributes is not supported."
case .unsupportedNumIndexes:
return "The number of indexes is not supported."
case .unsupportedNumRecordTypes:
return "The number of record types is not supported."
case .fieldSpecifiedMultiple:
return "Too many fields were specified."
case .incompatibleFieldFormat:
return "The field format was incompatible."
case .invalidParsingModule:
return "The parsing module was not valid."
case .databaseLocked:
return "The database is locked."
case .datastoreIsOpen:
return "The data store is open."
case .missingValue:
return "A missing value was detected."
case .unsupportedQueryLimits:
return "The query limits are not supported."
case .unsupportedNumSelectionPreds:
return "The number of selection predicates is not supported."
case .unsupportedOperator:
return "The operator is not supported."
case .invalidDBLocation:
return "The database location is not valid."
case .invalidAccessRequest:
return "The access request is not valid."
case .invalidIndexInfo:
return "The index information is not valid."
case .invalidNewOwner:
return "The new owner is not valid."
case .invalidModifyMode:
return "The modify mode is not valid."
case .missingRequiredExtension:
return "A required certificate extension is missing."
case .extendedKeyUsageNotCritical:
return "The extended key usage extension was not marked critical."
case .timestampMissing:
return "A timestamp was expected but was not found."
case .timestampInvalid:
return "The timestamp was not valid."
case .timestampNotTrusted:
return "The timestamp was not trusted."
case .timestampServiceNotAvailable:
return "The timestamp service is not available."
case .timestampBadAlg:
return "An unrecognized or unsupported Algorithm Identifier in timestamp."
case .timestampBadRequest:
return "The timestamp transaction is not permitted or supported."
case .timestampBadDataFormat:
return "The timestamp data submitted has the wrong format."
case .timestampTimeNotAvailable:
return "The time source for the Timestamp Authority is not available."
case .timestampUnacceptedPolicy:
return "The requested policy is not supported by the Timestamp Authority."
case .timestampUnacceptedExtension:
return "The requested extension is not supported by the Timestamp Authority."
case .timestampAddInfoNotAvailable:
return "The additional information requested is not available."
case .timestampSystemFailure:
return "The timestamp request cannot be handled due to system failure."
case .signingTimeMissing:
return "A signing time was expected but was not found."
case .timestampRejection:
return "A timestamp transaction was rejected."
case .timestampWaiting:
return "A timestamp transaction is waiting."
case .timestampRevocationWarning:
return "A timestamp authority revocation warning was issued."
case .timestampRevocationNotification:
return "A timestamp authority revocation notification was issued."
case .unexpectedError:
return "Unexpected error has occurred."
}
}
}
extension Status: CustomNSError {
public static let errorDomain = KeychainAccessErrorDomain
public var errorCode: Int {
return Int(rawValue)
}
public var errorUserInfo: [String : Any] {
return [NSLocalizedDescriptionKey: description]
}
}
================================================
FILE: External/SymbolPicker/.gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## User settings
xcuserdata/
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
## Obj-C/Swift specific
*.hmap
## App packaging
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build/
# Accio dependency management
Dependencies/
.accio/
# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/
.swiftpm/
.DS_Store
================================================
FILE: External/SymbolPicker/LICENSE
================================================
MIT License
Copyright (c) 2022 Yubo Qin & Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: External/SymbolPicker/Package.swift
================================================
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "SymbolPicker",
defaultLocalization: "en",
platforms: [
.iOS(.v14),
.macOS(.v12),
.tvOS(.v15),
.watchOS(.v8),
],
products: [
.library(
name: "SymbolPicker",
targets: ["SymbolPicker"]
),
],
dependencies: [
],
targets: [
.target(
name: "SymbolPicker",
dependencies: [],
path: "Sources/SymbolPicker",
resources: [
.process("Resources"),
]
),
]
)
================================================
FILE: External/SymbolPicker/README.md
================================================
# SymbolPicker
A simple and cross-platform SFSymbol picker for SwiftUI


## Features
SymbolPicker provides a simple and cross-platform interface for picking a SFSymbol with search functionality that is backported to iOS 14. SymbolPicker is implemented with SwiftUI and supports iOS, macOS, tvOS and watchOS platforms.

## Usage
### Requirements
* iOS 14.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+
* Xcode 13.0+
* Swift 5.0+
### Installation
SymbolPicker is available as a Swift Package. Add this repo to your project through Xcode GUI or `Package.swift`.
```swift
dependencies: [
.package(url: "https://github.com/xnth97/SymbolPicker.git", .upToNextMajor(from: "1.1.0"))
]
```
### Example
It is suggested to use SymbolPicker within a `sheet`.
```swift
import SwiftUI
import SymbolPicker
struct ContentView: View {
@State private var iconPickerPresented = false
@State private var icon = "pencil"
var body: some View {
Button(action: {
iconPickerPresented = true
}) {
HStack {
Image(systemName: icon)
Text(icon)
}
}
.sheet(isPresented: $iconPickerPresented) {
SymbolPicker(symbol: $icon)
}
}
}
```
## TODO
- [ ] Categories support
- [x] Multiplatform support
- [ ] Inline UI
- [ ] Codegen from latest SF Symbols
## License
SymbolPicker is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
================================================
FILE: External/SymbolPicker/Sources/SymbolPicker/Resources/en.lproj/Localizable.strings
================================================
"search_placeholder" = "Search";
"cancel" = "Cancel";
"sf_symbol_picker" = "Select a symbol";
"done" = "Done";
================================================
FILE: External/SymbolPicker/Sources/SymbolPicker/Resources/sfsymbols.txt
================================================
square.and.arrow.up
square.and.arrow.up.fill
square.and.arrow.up.circle
square.and.arrow.up.circle.fill
square.and.arrow.up.trianglebadge.exclamationmark
square.and.arrow.down
square.and.arrow.down.fill
square.and.arrow.up.on.square
square.and.arrow.up.on.square.fill
square.and.arrow.down.on.square
square.and.arrow.down.on.square.fill
rectangle.portrait.and.arrow.right
rectangle.portrait.and.arrow.right.fill
pencil
pencil.circle
pencil.circle.fill
pencil.slash
square.and.pencil
rectangle.and.pencil.and.ellipsis
scribble
scribble.variable
highlighter
pencil.and.outline
pencil.tip
pencil.tip.crop.circle
pencil.tip.crop.circle.badge.plus
pencil.tip.crop.circle.badge.minus
pencil.tip.crop.circle.badge.arrow.forward
lasso
lasso.and.sparkles
trash
trash.fill
trash.circle
trash.circle.fill
trash.square
trash.square.fill
trash.slash
trash.slash.fill
trash.slash.circle
trash.slash.circle.fill
trash.slash.square
trash.slash.square.fill
folder
folder.fill
folder.circle
folder.circle.fill
folder.badge.plus
folder.fill.badge.plus
folder.badge.minus
folder.fill.badge.minus
folder.badge.questionmark
folder.fill.badge.questionmark
folder.badge.person.crop
folder.fill.badge.person.crop
square.grid.3x1.folder.badge.plus
square.grid.3x1.folder.fill.badge.plus
folder.badge.gearshape
folder.fill.badge.gearshape
plus.rectangle.on.folder
plus.rectangle.on.folder.fill
questionmark.folder
questionmark.folder.fill
paperplane
paperplane.fill
paperplane.circle
paperplane.circle.fill
tray
tray.fill
tray.circle
tray.circle.fill
tray.and.arrow.up
tray.and.arrow.up.fill
tray.and.arrow.down
tray.and.arrow.down.fill
tray.2
tray.2.fill
tray.full
tray.full.fill
externaldrive
externaldrive.fill
externaldrive.badge.plus
externaldrive.fill.badge.plus
externaldrive.badge.minus
externaldrive.fill.badge.minus
externaldrive.badge.checkmark
externaldrive.fill.badge.checkmark
externaldrive.badge.xmark
externaldrive.fill.badge.xmark
externaldrive.badge.person.crop
externaldrive.fill.badge.person.crop
externaldrive.badge.icloud
externaldrive.fill.badge.icloud
externaldrive.badge.wifi
externaldrive.fill.badge.wifi
externaldrive.badge.timemachine
externaldrive.fill.badge.timemachine
internaldrive
internaldrive.fill
opticaldiscdrive
opticaldiscdrive.fill
externaldrive.connected.to.line.below
externaldrive.connected.to.line.below.fill
archivebox
archivebox.fill
archivebox.circle
archivebox.circle.fill
xmark.bin
xmark.bin.fill
xmark.bin.circle
xmark.bin.circle.fill
arrow.up.bin
arrow.up.bin.fill
doc
doc.fill
doc.circle
doc.circle.fill
doc.badge.plus
doc.fill.badge.plus
doc.badge.gearshape
doc.badge.gearshape.fill
doc.badge.ellipsis
doc.fill.badge.ellipsis
lock.doc
lock.doc.fill
arrow.up.doc
arrow.up.doc.fill
arrow.down.doc
arrow.down.doc.fill
doc.text
doc.text.fill
doc.zipper
doc.on.doc
doc.on.doc.fill
doc.on.clipboard
arrow.right.doc.on.clipboard
arrow.up.doc.on.clipboard
arrow.triangle.2.circlepath.doc.on.clipboard
doc.on.clipboard.fill
doc.richtext
doc.richtext.fill
doc.plaintext
doc.plaintext.fill
doc.append
doc.append.fill
doc.text.below.ecg
doc.text.below.ecg.fill
chart.bar.doc.horizontal
chart.bar.doc.horizontal.fill
list.bullet.rectangle.portrait
list.bullet.rectangle.portrait.fill
doc.text.magnifyingglass
list.bullet.rectangle
list.bullet.rectangle.fill
list.dash.header.rectangle
terminal
terminal.fill
note
note.text
note.text.badge.plus
calendar
calendar.circle
calendar.circle.fill
calendar.badge.plus
calendar.badge.minus
calendar.badge.clock
calendar.badge.exclamationmark
calendar.day.timeline.left
calendar.day.timeline.right
calendar.day.timeline.leading
calendar.day.timeline.trailing
arrowshape.turn.up.left
arrowshape.turn.up.left.fill
arrowshape.turn.up.left.circle
arrowshape.turn.up.left.circle.fill
arrowshape.turn.up.backward
arrowshape.turn.up.backward.fill
arrowshape.turn.up.backward.circle
arrowshape.turn.up.backward.circle.fill
arrowshape.turn.up.right
arrowshape.turn.up.right.fill
arrowshape.turn.up.right.circle
arrowshape.turn.up.right.circle.fill
arrowshape.turn.up.forward
arrowshape.turn.up.forward.fill
arrowshape.turn.up.forward.circle
arrowshape.turn.up.forward.circle.fill
arrowshape.turn.up.left.2
arrowshape.turn.up.left.2.fill
arrowshape.turn.up.left.2.circle
arrowshape.turn.up.left.2.circle.fill
arrowshape.turn.up.backward.2
arrowshape.turn.up.backward.2.fill
arrowshape.turn.up.backward.2.circle
arrowshape.turn.up.backward.2.circle.fill
arrowshape.zigzag.right
arrowshape.zigzag.right.fill
arrowshape.zigzag.forward
arrowshape.zigzag.forward.fill
arrowshape.bounce.right
arrowshape.bounce.right.fill
arrowshape.bounce.forward
arrowshape.bounce.forward.fill
book
book.fill
book.circle
book.circle.fill
books.vertical
books.vertical.fill
books.vertical.circle
books.vertical.circle.fill
book.closed
book.closed.fill
book.closed.circle
book.closed.circle.fill
character.book.closed
character.book.closed.fill
text.book.closed
text.book.closed.fill
menucard
menucard.fill
greetingcard
greetingcard.fill
magazine
magazine.fill
newspaper
newspaper.fill
newspaper.circle
newspaper.circle.fill
heart.text.square
heart.text.square.fill
square.text.square
square.text.square.fill
doc.text.image
doc.text.image.fill
bookmark
bookmark.fill
bookmark.circle
bookmark.circle.fill
bookmark.square
bookmark.square.fill
bookmark.slash
bookmark.slash.fill
rosette
graduationcap
graduationcap.fill
graduationcap.circle
graduationcap.circle.fill
ticket
ticket.fill
paperclip
paperclip.circle
paperclip.circle.fill
paperclip.badge.ellipsis
rectangle.and.paperclip
rectangle.dashed.and.paperclip
link
link.circle
link.circle.fill
link.badge.plus
personalhotspot
personalhotspot.circle
personalhotspot.circle.fill
lineweight
person
person.fill
person.fill.turn.right
person.fill.turn.down
person.fill.turn.left
person.fill.checkmark
person.fill.xmark
person.fill.questionmark
person.circle
person.circle.fill
person.badge.plus
person.fill.badge.plus
person.badge.minus
person.fill.badge.minus
person.badge.clock
person.badge.clock.fill
shareplay
shareplay.slash
rectangle.inset.filled.and.person.filled
person.and.arrow.left.and.arrow.right
person.fill.and.arrow.left.and.arrow.right
person.2
person.2.fill
person.2.circle
person.2.circle.fill
person.wave.2
person.wave.2.fill
person.2.wave.2
person.2.wave.2.fill
person.3
person.3.fill
person.3.sequence
person.3.sequence.fill
lanyardcard
lanyardcard.fill
person.crop.circle
person.crop.circle.fill
person.crop.circle.badge.plus
person.crop.circle.fill.badge.plus
person.crop.circle.badge.minus
person.crop.circle.fill.badge.minus
person.crop.circle.badge.checkmark
person.crop.circle.fill.badge.checkmark
person.crop.circle.badge.xmark
person.crop.circle.fill.badge.xmark
person.crop.circle.badge.questionmark
person.crop.circle.badge.questionmark.fill
person.crop.circle.badge.exclamationmark
person.crop.circle.badge.exclamationmark.fill
person.crop.circle.badge.moon
person.crop.circle.badge.moon.fill
person.crop.circle.badge.clock
person.crop.circle.badge.clock.fill
person.crop.circle.badge
person.crop.circle.badge.fill
person.crop.square
person.crop.square.fill
person.crop.artframe
photo.artframe
person.crop.rectangle.stack
person.crop.rectangle.stack.fill
person.2.crop.square.stack
person.2.crop.square.stack.fill
person.crop.rectangle
person.crop.rectangle.fill
arrow.up.and.person.rectangle.portrait
arrow.up.and.person.rectangle.turn.right
arrow.up.and.person.rectangle.turn.left
person.crop.square.filled.and.at.rectangle
person.crop.square.filled.and.at.rectangle.fill
square.and.at.rectangle
square.and.at.rectangle.fill
person.text.rectangle
person.text.rectangle.fill
command
command.circle
command.circle.fill
command.square
command.square.fill
option
alt
clear
clear.fill
delete.left
delete.left.fill
delete.backward
delete.backward.fill
delete.right
delete.right.fill
delete.forward
delete.forward.fill
shift
shift.fill
capslock
capslock.fill
escape
restart
restart.circle
restart.circle.fill
sleep
sleep.circle
sleep.circle.fill
wake
wake.circle
wake.circle.fill
power
power.circle
power.circle.fill
power.dotted
togglepower
poweron
poweroff
powersleep
directcurrent
alternatingcurrent
peacesign
dot.arrowtriangles.up.right.down.left.circle
globe
globe.badge.chevron.backward
network
network.badge.shield.half.filled
globe.americas
globe.americas.fill
globe.europe.africa
globe.europe.africa.fill
globe.asia.australia
globe.asia.australia.fill
sun.min
sun.min.fill
sun.max
sun.max.fill
sun.max.circle
sun.max.circle.fill
sunrise
sunrise.fill
sunset
sunset.fill
sun.and.horizon
sun.and.horizon.fill
sun.dust
sun.dust.fill
sun.haze
sun.haze.fill
moon
moon.fill
moon.circle
moon.circle.fill
zzz
moon.zzz
moon.zzz.fill
sparkle
sparkles
moon.stars
moon.stars.fill
cloud
cloud.fill
cloud.drizzle
cloud.drizzle.fill
cloud.rain
cloud.rain.fill
cloud.heavyrain
cloud.heavyrain.fill
cloud.fog
cloud.fog.fill
cloud.hail
cloud.hail.fill
cloud.snow
cloud.snow.fill
cloud.sleet
cloud.sleet.fill
cloud.bolt
cloud.bolt.fill
cloud.bolt.rain
cloud.bolt.rain.fill
cloud.sun
cloud.sun.fill
cloud.sun.rain
cloud.sun.rain.fill
cloud.sun.bolt
cloud.sun.bolt.fill
cloud.moon
cloud.moon.fill
cloud.moon.rain
cloud.moon.rain.fill
cloud.moon.bolt
cloud.moon.bolt.fill
smoke
smoke.fill
wind
wind.snow
snowflake
snowflake.circle
snowflake.circle.fill
tornado
tropicalstorm
hurricane
thermometer.sun
thermometer.sun.fill
thermometer.snowflake
thermometer
aqi.low
aqi.medium
aqi.high
humidity
humidity.fill
umbrella
umbrella.fill
flame
flame.fill
flame.circle
flame.circle.fill
light.min
light.max
rays
slowmo
timelapse
cursorarrow.rays
cursorarrow
cursorarrow.square
cursorarrow.and.square.on.square.dashed
cursorarrow.click
cursorarrow.click.2
contextualmenu.and.cursorarrow
filemenu.and.cursorarrow
filemenu.and.selection
dot.circle.and.hand.point.up.left.fill
dot.circle.and.cursorarrow
cursorarrow.motionlines
cursorarrow.motionlines.click
cursorarrow.click.badge.clock
keyboard
keyboard.fill
keyboard.badge.ellipsis
keyboard.chevron.compact.down
keyboard.chevron.compact.left
keyboard.onehanded.left
keyboard.onehanded.right
rectangle.3.group
rectangle.3.group.fill
square.grid.3x2
square.grid.3x2.fill
rectangle.grid.3x2
rectangle.grid.3x2.fill
square.grid.2x2
square.grid.2x2.fill
rectangle.grid.2x2
rectangle.grid.2x2.fill
square.grid.3x1.below.line.grid.1x2
square.grid.3x1.below.line.grid.1x2.fill
square.grid.4x3.fill
rectangle.grid.1x2
rectangle.grid.1x2.fill
circle.grid.2x2
circle.grid.2x2.fill
circle.grid.3x3
circle.grid.3x3.fill
circle.grid.3x3.circle
circle.grid.3x3.circle.fill
square.grid.3x3
square.grid.3x3.fill
square.grid.3x3.topleft.filled
square.grid.3x3.topmiddle.filled
square.grid.3x3.topright.filled
square.grid.3x3.middleleft.filled
square.grid.3x3.middle.filled
square.grid.3x3.middleright.filled
square.grid.3x3.bottomleft.filled
square.grid.3x3.bottommiddle.filled
square.grid.3x3.bottomright.filled
circle.hexagongrid
circle.hexagongrid.fill
circle.hexagongrid.circle
circle.hexagongrid.circle.fill
circle.hexagonpath
circle.hexagonpath.fill
circle.grid.cross
circle.grid.cross.fill
circle.grid.cross.left.filled
circle.grid.cross.up.filled
circle.grid.cross.right.filled
circle.grid.cross.down.filled
seal
seal.fill
checkmark.seal
checkmark.seal.fill
xmark.seal
xmark.seal.fill
exclamationmark.triangle
exclamationmark.triangle.fill
drop
drop.fill
drop.circle
drop.circle.fill
drop.triangle
drop.triangle.fill
play
play.fill
play.circle
play.circle.fill
play.square
play.square.fill
play.rectangle
play.rectangle.fill
play.slash
play.slash.fill
pause
pause.fill
pause.circle
pause.circle.fill
pause.rectangle
pause.rectangle.fill
stop
stop.fill
stop.circle
stop.circle.fill
record.circle
record.circle.fill
playpause
playpause.fill
backward
backward.fill
backward.circle
backward.circle.fill
forward
forward.fill
forward.circle
forward.circle.fill
backward.end
backward.end.fill
forward.end
forward.end.fill
backward.end.alt
backward.end.alt.fill
forward.end.alt
forward.end.alt.fill
backward.frame
backward.frame.fill
forward.frame
forward.frame.fill
eject
eject.fill
eject.circle
eject.circle.fill
mount
mount.fill
memories
memories.badge.plus
memories.badge.minus
shuffle
shuffle.circle
shuffle.circle.fill
repeat
repeat.circle
repeat.circle.fill
repeat.1
repeat.1.circle
repeat.1.circle.fill
infinity
infinity.circle
infinity.circle.fill
megaphone
megaphone.fill
speaker
speaker.fill
speaker.circle
speaker.circle.fill
speaker.slash
speaker.slash.fill
speaker.slash.circle
speaker.slash.circle.fill
speaker.zzz
speaker.zzz.fill
speaker.wave.1
speaker.wave.1.fill
speaker.wave.2
speaker.wave.2.fill
speaker.wave.2.circle
speaker.wave.2.circle.fill
speaker.wave.3
speaker.wave.3.fill
speaker.badge.exclamationmark
speaker.badge.exclamationmark.fill
badge.plus.radiowaves.right
badge.plus.radiowaves.forward
music.note
music.note.list
music.quarternote.3
music.mic
music.mic.circle
music.mic.circle.fill
arrow.rectanglepath
goforward
gobackward
goforward.5
gobackward.5
goforward.10
gobackward.10
goforward.15
gobackward.15
goforward.30
gobackward.30
goforward.45
gobackward.45
goforward.60
gobackward.60
goforward.75
gobackward.75
goforward.90
gobackward.90
goforward.plus
gobackward.minus
swift
magnifyingglass
magnifyingglass.circle
magnifyingglass.circle.fill
plus.magnifyingglass
minus.magnifyingglass
1.magnifyingglass
arrow.up.left.and.down.right.magnifyingglass
text.magnifyingglass
sparkle.magnifyingglass
location.magnifyingglass
loupe
mic
mic.fill
mic.circle
mic.circle.fill
mic.square
mic.square.fill
mic.slash
mic.slash.fill
mic.slash.circle
mic.slash.circle.fill
mic.badge.plus
mic.fill.badge.plus
line.diagonal
line.diagonal.arrow
circle
circle.fill
circle.slash
circle.slash.fill
circle.lefthalf.filled
circle.righthalf.filled
circle.tophalf.filled
circle.bottomhalf.filled
circle.inset.filled
smallcircle.filled.circle
smallcircle.filled.circle.fill
circle.dashed
circle.dashed.inset.filled
circle.dotted
circlebadge
circlebadge.fill
circlebadge.2
circlebadge.2.fill
smallcircle.circle
smallcircle.circle.fill
target
capsule
capsule.fill
capsule.lefthalf.filled
capsule.righthalf.filled
capsule.tophalf.filled
capsule.bottomhalf.filled
capsule.inset.filled
capsule.portrait
capsule.portrait.fill
capsule.portrait.lefthalf.filled
capsule.portrait.righthalf.filled
capsule.portrait.tophalf.filled
capsule.portrait.bottomhalf.filled
capsule.portrait.inset.filled
oval
oval.fill
oval.lefthalf.filled
oval.righthalf.filled
oval.tophalf.filled
oval.bottomhalf.filled
oval.inset.filled
oval.portrait
oval.portrait.fill
oval.portrait.lefthalf.filled
oval.portrait.righthalf.filled
oval.portrait.tophalf.filled
oval.portrait.bottomhalf.filled
oval.portrait.inset.filled
placeholdertext.fill
square
square.fill
square.slash
square.slash.fill
square.lefthalf.filled
square.righthalf.filled
square.tophalf.filled
square.bottomhalf.filled
square.inset.filled
square.split.2x1
square.split.2x1.fill
square.split.1x2
square.split.1x2.fill
square.split.2x2
square.split.2x2.fill
square.split.diagonal.2x2
square.split.diagonal.2x2.fill
square.split.diagonal
square.split.diagonal.fill
dot.square
dot.square.fill
circle.square
circle.square.fill
square.dashed
square.dashed.inset.filled
plus.square.dashed
questionmark.square.dashed
square.on.square
square.fill.on.square.fill
square.filled.on.square
hand.raised.square.on.square
hand.raised.square.on.square.fill
sparkles.square.filled.on.square
square.on.square.dashed
plus.square.on.square
plus.square.fill.on.square.fill
square.on.circle
square.fill.on.circle.fill
r.square.on.square
r.square.on.square.fill
j.square.on.square
j.square.on.square.fill
h.square.on.square
h.square.on.square.fill
square.stack
square.stack.fill
squareshape
squareshape.fill
squareshape.dashed.squareshape
squareshape.squareshape.dashed
dot.squareshape
dot.squareshape.fill
app
app.fill
rectangle
rectangle.fill
rectangle.slash
rectangle.slash.fill
rectangle.lefthalf.filled
rectangle.righthalf.filled
rectangle.leadinghalf.filled
rectangle.trailinghalf.filled
rectangle.tophalf.filled
rectangle.bottomhalf.filled
rectangle.split.2x1
rectangle.split.2x1.fill
rectangle.split.2x1.slash
rectangle.split.2x1.slash.fill
rectangle.split.1x2
rectangle.split.1x2.fill
rectangle.split.3x1
rectangle.split.3x1.fill
rectangle.split.2x2
rectangle.split.2x2.fill
tablecells
tablecells.fill
tablecells.badge.ellipsis
tablecells.fill.badge.ellipsis
rectangle.split.3x3
rectangle.inset.filled
rectangle.tophalf.inset.filled
rectangle.bottomhalf.inset.filled
rectangle.lefthalf.inset.filled
rectangle.righthalf.inset.filled
rectangle.leadinghalf.inset.filled
rectangle.trailinghalf.inset.filled
rectangle.lefthalf.inset.filled.arrow.left
rectangle.righthalf.inset.filled.arrow.right
rectangle.leadinghalf.inset.filled.arrow.leading
rectangle.trailinghalf.inset.filled.arrow.trailing
rectangle.topthird.inset.filled
rectangle.bottomthird.inset.filled
rectangle.leftthird.inset.filled
rectangle.rightthird.inset.filled
rectangle.leadingthird.inset.filled
rectangle.trailingthird.inset.filled
rectangle.center.inset.filled
rectangle.center.inset.filled.badge.plus
rectangle.inset.topleft.filled
rectangle.inset.topright.filled
rectangle.inset.topleading.filled
rectangle.inset.toptrailing.filled
rectangle.inset.bottomleft.filled
rectangle.inset.bottomright.filled
rectangle.inset.bottomleading.filled
rectangle.inset.bottomtrailing.filled
rectangle.on.rectangle
rectangle.fill.on.rectangle.fill
rectangle.on.rectangle.circle
rectangle.on.rectangle.circle.fill
rectangle.on.rectangle.square
rectangle.on.rectangle.square.fill
rectangle.inset.filled.on.rectangle
rectangle.on.rectangle.slash
rectangle.on.rectangle.slash.fill
rectangle.on.rectangle.slash.circle
rectangle.on.rectangle.slash.circle.fill
play.rectangle.on.rectangle
play.rectangle.on.rectangle.fill
play.rectangle.on.rectangle.circle
play.rectangle.on.rectangle.circle.fill
plus.rectangle.on.rectangle
plus.rectangle.fill.on.rectangle.fill
rectangle.portrait
rectangle.portrait.fill
rectangle.portrait.slash
rectangle.portrait.slash.fill
rectangle.portrait.lefthalf.filled
rectangle.portrait.righthalf.filled
rectangle.portrait.tophalf.filled
rectangle.portrait.bottomhalf.filled
rectangle.portrait.inset.filled
rectangle.portrait.tophalf.inset.filled
rectangle.portrait.bottomhalf.inset.filled
rectangle.portrait.lefthalf.inset.filled
rectangle.portrait.righthalf.inset.filled
rectangle.portrait.leadinghalf.inset.filled
rectangle.portrait.trailinghalf.inset.filled
rectangle.portrait.topthird.inset.filled
rectangle.portrait.bottomthird.inset.filled
rectangle.portrait.leftthird.inset.filled
rectangle.portrait.rightthird.inset.filled
rectangle.portrait.leadingthird.inset.filled
rectangle.portrait.trailingthird.inset.filled
rectangle.portrait.center.inset.filled
rectangle.portrait.topleft.inset.filled
rectangle.portrait.topright.inset.filled
rectangle.portrait.topleading.inset.filled
rectangle.portrait.toptrailing.inset.filled
rectangle.portrait.bottomleft.inset.filled
rectangle.portrait.bottomright.inset.filled
rectangle.portrait.bottomleading.inset.filled
rectangle.portrait.bottomtrailing.inset.filled
rectangle.portrait.on.rectangle.portrait
rectangle.portrait.on.rectangle.portrait.fill
rectangle.portrait.on.rectangle.portrait.slash
rectangle.portrait.on.rectangle.portrait.slash.fill
rectangle.portrait.split.2x1
rectangle.portrait.split.2x1.fill
rectangle.portrait.split.2x1.slash
rectangle.portrait.split.2x1.slash.fill
triangle
triangle.fill
triangle.lefthalf.filled
triangle.righthalf.filled
triangle.tophalf.filled
triangle.bottomhalf.filled
triangle.inset.filled
diamond
diamond.fill
diamond.circle
diamond.circle.fill
diamond.lefthalf.filled
diamond.righthalf.filled
diamond.tophalf.filled
diamond.bottomhalf.filled
diamond.inset.filled
octagon
octagon.fill
octagon.lefthalf.filled
octagon.righthalf.filled
octagon.tophalf.filled
octagon.bottomhalf.filled
hexagon
hexagon.fill
hexagon.lefthalf.filled
hexagon.righthalf.filled
hexagon.tophalf.filled
hexagon.bottomhalf.filled
pentagon
pentagon.fill
pentagon.lefthalf.filled
pentagon.righthalf.filled
pentagon.tophalf.filled
pentagon.bottomhalf.filled
suit.heart
suit.heart.fill
suit.club
suit.club.fill
suit.spade
suit.spade.fill
suit.diamond
suit.diamond.fill
heart
heart.fill
heart.circle
heart.circle.fill
heart.square
heart.square.fill
heart.rectangle
heart.rectangle.fill
heart.slash
heart.slash.fill
heart.slash.circle
heart.slash.circle.fill
bolt.heart
bolt.heart.fill
arrow.up.heart
arrow.up.heart.fill
arrow.down.heart
arrow.down.heart.fill
arrow.clockwise.heart
arrow.clockwise.heart.fill
rhombus
rhombus.fill
star
star.fill
star.leadinghalf.filled
star.circle
star.circle.fill
star.square
star.square.fill
star.slash
star.slash.fill
line.horizontal.star.fill.line.horizontal
flag
flag.fill
flag.circle
flag.circle.fill
flag.square
flag.square.fill
flag.slash
flag.slash.fill
flag.slash.circle
flag.slash.circle.fill
flag.badge.ellipsis
flag.badge.ellipsis.fill
flag.2.crossed
flag.2.crossed.fill
flag.filled.and.flag.crossed
flag.and.flag.filled.crossed
location
location.fill
location.circle
location.circle.fill
location.square
location.square.fill
location.slash
location.slash.fill
location.north
location.north.fill
location.north.circle
location.north.circle.fill
location.north.line
location.north.line.fill
sensor.tag.radiowaves.forward
sensor.tag.radiowaves.forward.fill
airtag.radiowaves.forward
airtag.radiowaves.forward.fill
airtag
airtag.fill
bell
bell.fill
bell.circle
bell.circle.fill
bell.square
bell.square.fill
bell.slash
bell.slash.fill
bell.slash.circle
bell.slash.circle.fill
bell.and.waveform
bell.and.waveform.fill
bell.badge
bell.badge.fill
bell.badge.circle
bell.badge.circle.fill
tag
tag.fill
tag.circle
tag.circle.fill
tag.square
tag.square.fill
tag.slash
tag.slash.fill
bolt
bolt.fill
bolt.circle
bolt.circle.fill
bolt.square
bolt.square.fill
bolt.ring.closed
bolt.shield
bolt.shield.fill
bolt.slash
bolt.slash.fill
bolt.slash.circle
bolt.slash.circle.fill
bolt.badge.a
bolt.badge.a.fill
bolt.horizontal
bolt.horizontal.fill
bolt.horizontal.circle
bolt.horizontal.circle.fill
eye
eye.fill
eye.circle
eye.circle.fill
eye.square
eye.square.fill
eye.slash
eye.slash.fill
eye.slash.circle
eye.slash.circle.fill
eye.trianglebadge.exclamationmark
eye.trianglebadge.exclamationmark.fill
tshirt
tshirt.fill
eyes
eyes.inverse
eyebrow
nose
nose.fill
mustache
mustache.fill
mouth
mouth.fill
eyeglasses
facemask
facemask.fill
brain.head.profile
brain
icloud
icloud.fill
icloud.circle
icloud.circle.fill
icloud.square
icloud.square.fill
icloud.slash
icloud.slash.fill
exclamationmark.icloud
exclamationmark.icloud.fill
checkmark.icloud
checkmark.icloud.fill
xmark.icloud
xmark.icloud.fill
link.icloud
link.icloud.fill
bolt.horizontal.icloud
bolt.horizontal.icloud.fill
person.icloud
person.icloud.fill
lock.icloud
lock.icloud.fill
key.icloud
key.icloud.fill
arrow.clockwise.icloud
arrow.clockwise.icloud.fill
arrow.counterclockwise.icloud
arrow.counterclockwise.icloud.fill
icloud.and.arrow.down
icloud.and.arrow.down.fill
icloud.and.arrow.up
icloud.and.arrow.up.fill
flashlight.off.fill
flashlight.on.fill
camera
camera.fill
camera.circle
camera.circle.fill
camera.shutter.button
camera.shutter.button.fill
camera.badge.ellipsis
camera.fill.badge.ellipsis
arrow.triangle.2.circlepath.camera
arrow.triangle.2.circlepath.camera.fill
camera.on.rectangle
camera.on.rectangle.fill
message
message.fill
message.circle
message.circle.fill
message.and.waveform
message.and.waveform.fill
arrow.up.message
arrow.up.message.fill
plus.message
plus.message.fill
bubble.right
bubble.right.fill
bubble.right.circle
bubble.right.circle.fill
bubble.left
bubble.left.fill
bubble.left.circle
bubble.left.circle.fill
exclamationmark.bubble
exclamationmark.bubble.fill
exclamationmark.bubble.circle
exclamationmark.bubble.circle.fill
quote.opening
quote.closing
quote.bubble
quote.bubble.fill
star.bubble
star.bubble.fill
character.bubble
character.bubble.fill
text.bubble
text.bubble.fill
captions.bubble
captions.bubble.fill
plus.bubble
plus.bubble.fill
checkmark.bubble
checkmark.bubble.fill
rectangle.3.group.bubble.left
rectangle.3.group.bubble.left.fill
ellipsis.bubble
ellipsis.bubble.fill
ellipsis.vertical.bubble
ellipsis.vertical.bubble.fill
phone.bubble.left
phone.bubble.left.fill
video.bubble.left
video.bubble.left.fill
bubble.middle.bottom
bubble.middle.bottom.fill
bubble.middle.top
bubble.middle.top.fill
bubble.left.and.bubble.right
bubble.left.and.bubble.right.fill
bubble.left.and.exclamationmark.bubble.right
bubble.left.and.exclamationmark.bubble.right.fill
phone
phone.fill
phone.circle
phone.circle.fill
phone.badge.plus
phone.fill.badge.plus
phone.connection
phone.fill.connection
phone.and.waveform
phone.and.waveform.fill
phone.arrow.up.right
phone.fill.arrow.up.right
phone.arrow.down.left
phone.fill.arrow.down.left
phone.arrow.right
phone.fill.arrow.right
phone.down
phone.down.fill
phone.down.circle
phone.down.circle.fill
teletype
teletype.circle
teletype.circle.fill
teletype.answer
teletype.answer.circle
teletype.answer.circle.fill
video
video.fill
video.circle
video.circle.fill
video.square
video.square.fill
video.slash
video.slash.fill
video.badge.plus
video.fill.badge.plus
video.badge.checkmark
video.fill.badge.checkmark
video.badge.ellipsis
video.fill.badge.ellipsis
video.and.waveform
video.and.waveform.fill
arrow.up.right.video
arrow.up.right.video.fill
arrow.down.left.video
arrow.down.left.video.fill
questionmark.video
questionmark.video.fill
envelope
envelope.fill
envelope.circle
envelope.circle.fill
envelope.arrow.triangle.branch
envelope.arrow.triangle.branch.fill
envelope.open
envelope.open.fill
envelope.badge
envelope.badge.fill
envelope.badge.shield.half.filled
envelope.badge.shield.half.filled.fill
mail.stack
mail.stack.fill
mail
mail.fill
mail.and.text.magnifyingglass
rectangle.and.text.magnifyingglass
arrow.up.right.and.arrow.down.left.rectangle
arrow.up.right.and.arrow.down.left.rectangle.fill
gear
gear.circle
gear.circle.fill
gear.badge.checkmark
gear.badge.xmark
gear.badge.questionmark
gearshape
gearshape.fill
gearshape.circle
gearshape.circle.fill
gearshape.2
gearshape.2.fill
signature
line.3.crossed.swirl.circle
line.3.crossed.swirl.circle.fill
scissors
scissors.circle
scissors.circle.fill
scissors.badge.ellipsis
ellipsis
ellipsis.circle
ellipsis.circle.fill
ellipsis.rectangle
ellipsis.rectangle.fill
bag
bag.fill
bag.circle
bag.circle.fill
bag.badge.plus
bag.fill.badge.plus
bag.badge.minus
bag.fill.badge.minus
cart
cart.fill
cart.circle
cart.circle.fill
cart.badge.plus
cart.fill.badge.plus
cart.badge.minus
cart.fill.badge.minus
creditcard
creditcard.fill
creditcard.circle
creditcard.circle.fill
creditcard.and.123
creditcard.trianglebadge.exclamationmark
giftcard
giftcard.fill
wallet.pass
wallet.pass.fill
wand.and.rays
wand.and.rays.inverse
wand.and.stars
wand.and.stars.inverse
crop
crop.rotate
dial.min
dial.min.fill
dial.max
dial.max.fill
gyroscope
nosign
gauge
gauge.badge.plus
gauge.badge.minus
speedometer
barometer
metronome
metronome.fill
amplifier
dice
dice.fill
die.face.1
die.face.1.fill
die.face.2
die.face.2.fill
die.face.3
die.face.3.fill
die.face.4
die.face.4.fill
die.face.5
die.face.5.fill
die.face.6
die.face.6.fill
square.grid.3x3.square
pianokeys
pianokeys.inverse
tuningfork
paintbrush
paintbrush.fill
paintbrush.pointed
paintbrush.pointed.fill
bandage
bandage.fill
ruler
ruler.fill
level
level.fill
lines.measurement.horizontal
wrench
wrench.fill
hammer
hammer.fill
hammer.circle
hammer.circle.fill
screwdriver
screwdriver.fill
eyedropper
eyedropper.halffull
eyedropper.full
wrench.and.screwdriver
wrench.and.screwdriver.fill
applescript
applescript.fill
scroll
scroll.fill
stethoscope
stethoscope.circle
stethoscope.circle.fill
printer
printer.fill
printer.filled.and.paper
printer.dotmatrix
printer.dotmatrix.fill
printer.dotmatrix.filled.and.paper
scanner
scanner.fill
faxmachine
briefcase
briefcase.fill
briefcase.circle
briefcase.circle.fill
case
case.fill
latch.2.case
latch.2.case.fill
cross.case
cross.case.fill
suitcase
suitcase.fill
suitcase.cart
suitcase.cart.fill
theatermasks
theatermasks.fill
theatermasks.circle
theatermasks.circle.fill
puzzlepiece.extension
puzzlepiece.extension.fill
puzzlepiece
puzzlepiece.fill
homekit
house
house.fill
house.circle
house.circle.fill
music.note.house
music.note.house.fill
building.columns
building.columns.fill
building.columns.circle
building.columns.circle.fill
signpost.left
signpost.left.fill
signpost.right
signpost.right.fill
square.split.bottomrightquarter
square.split.bottomrightquarter.fill
building
building.fill
building.2
building.2.fill
building.2.crop.circle
building.2.crop.circle.fill
lock
lock.fill
lock.circle
lock.circle.fill
lock.square
lock.square.fill
lock.square.stack
lock.square.stack.fill
lock.rectangle
lock.rectangle.fill
lock.rectangle.stack
lock.rectangle.stack.fill
lock.rectangle.on.rectangle
lock.rectangle.on.rectangle.fill
lock.shield
lock.shield.fill
lock.slash
lock.slash.fill
lock.open
lock.open.fill
lock.rotation
lock.rotation.open
key
key.fill
wifi
wifi.circle
wifi.circle.fill
wifi.square
wifi.square.fill
wifi.slash
wifi.exclamationmark
pin
pin.fill
pin.circle
pin.circle.fill
pin.square
pin.square.fill
pin.slash
pin.slash.fill
mappin
mappin.circle
mappin.circle.fill
mappin.square
mappin.square.fill
mappin.slash
mappin.slash.circle
mappin.slash.circle.fill
mappin.and.ellipse
map
map.fill
map.circle
map.circle.fill
safari
safari.fill
move.3d
scale.3d
rotate.3d
torus
rotate.left
rotate.left.fill
rotate.right
rotate.right.fill
selection.pin.in.out
powerplug
powerplug.fill
timeline.selection
cpu
cpu.fill
memorychip
memorychip.fill
opticaldisc
display
lock.display
lock.open.display
display.and.arrow.down
display.trianglebadge.exclamationmark
display.2
desktopcomputer
lock.desktopcomputer
lock.open.desktopcomputer
desktopcomputer.and.arrow.down
desktopcomputer.trianglebadge.exclamationmark
pc
macpro.gen1
macpro.gen1.fill
macpro.gen2
macpro.gen2.fill
macpro.gen3
macpro.gen3.fill
macpro.gen3.server
server.rack
xserve
laptopcomputer
lock.laptopcomputer
lock.open.laptopcomputer
laptopcomputer.and.arrow.down
laptopcomputer.trianglebadge.exclamationmark
laptopcomputer.and.iphone
ipad.and.iphone
macmini
macmini.fill
airport.express
airport.extreme
airport.extreme.tower
ipod
ipodshuffle.gen1
ipodshuffle.gen2
ipodshuffle.gen3
ipodshuffle.gen4
ipodtouch
ipodtouch.slash
ipodtouch.landscape
flipphone
candybarphone
iphone.homebutton
iphone.homebutton.circle
iphone.homebutton.circle.fill
iphone.homebutton.landscape
iphone.homebutton.radiowaves.left.and.right
iphone.homebutton.radiowaves.left.and.right.circle
iphone.homebutton.radiowaves.left.and.right.circle.fill
iphone.homebutton.slash
iphone.homebutton.slash.circle
iphone.homebutton.slash.circle.fill
iphone.homebutton.badge.play
iphone
iphone.circle
iphone.circle.fill
iphone.landscape
iphone.radiowaves.left.and.right
iphone.radiowaves.left.and.right.circle
iphone.radiowaves.left.and.right.circle.fill
iphone.slash
iphone.slash.circle
iphone.slash.circle.fill
iphone.badge.play
lock.iphone
lock.open.iphone
iphone.and.arrow.forward
arrow.turn.up.forward.iphone
arrow.turn.up.forward.iphone.fill
iphone.rear.camera
apps.iphone
apps.iphone.badge.plus
apps.iphone.landscape
platter.filled.top.iphone
platter.filled.bottom.iphone
platter.filled.top.and.arrow.up.iphone
platter.filled.bottom.and.arrow.down.iphone
platter.2.filled.iphone
platter.2.filled.iphone.landscape
iphone.smartbatterycase.gen2
iphone.smartbatterycase.gen1
ipad.homebutton
ipad.homebutton.badge.play
ipad.homebutton.landscape
ipad.homebutton.landscape.badge.play
ipad
ipad.badge.play
lock.ipad
lock.open.ipad
ipad.and.arrow.forward
ipad.landscape
ipad.landscape.badge.play
ipad.rear.camera
apps.ipad
apps.ipad.landscape
platter.2.filled.ipad
platter.2.filled.ipad.landscape
applepencil
magicmouse
magicmouse.fill
computermouse
computermouse.fill
applewatch
applewatch.watchface
exclamationmark.applewatch
lock.applewatch
lock.open.applewatch
applewatch.radiowaves.left.and.right
applewatch.slash
applewatch.side.right
watchface.applewatch.case
applewatch.case.inset.filled
platter.filled.top.applewatch.case
platter.filled.bottom.applewatch.case
platter.top.applewatch.case
platter.bottom.applewatch.case
digitalcrown.arrow.clockwise
digitalcrown.arrow.clockwise.fill
digitalcrown.arrow.counterclockwise
digitalcrown.arrow.counterclockwise.fill
digitalcrown.press
digitalcrown.press.fill
digitalcrown.horizontal.arrow.clockwise
digitalcrown.horizontal.arrow.clockwise.fill
digitalcrown.horizontal.arrow.counterclockwise
digitalcrown.horizontal.arrow.counterclockwise.fill
digitalcrown.horizontal.press
digitalcrown.horizontal.press.fill
airpodsmax
beats.headphones
headphones
headphones.circle
headphones.circle.fill
earbuds
earbuds.case
earbuds.case.fill
earpods
airpods
airpod.right
airpod.left
airpods.chargingcase
airpods.chargingcase.fill
airpods.chargingcase.wireless
airpods.chargingcase.wireless.fill
airpodspro
airpodpro.right
airpodpro.left
airpodspro.chargingcase.wireless
airpodspro.chargingcase.wireless.fill
airpods.gen3
airpod.gen3.right
airpod.gen3.left
airpods.gen3.chargingcase.wireless
airpods.gen3.chargingcase.wireless.fill
beats.earphones
beats.powerbeatspro
beats.powerbeatspro.right
beats.powerbeatspro.left
beats.powerbeats
beats.powerbeats3
beats.studiobuds
beats.studiobud.left
beats.studiobud.right
beats.studiobuds.chargingcase
beats.studiobuds.chargingcase.fill
beats.fit.pro
beats.fit.pro.left
beats.fit.pro.right
beats.fit.pro.chargingcase
beats.fit.pro.chargingcase.fill
beats.powerbeatspro.chargingcase
beats.powerbeatspro.chargingcase.fill
homepodmini
homepodmini.fill
homepodmini.2
homepodmini.2.fill
homepod.and.homepodmini
homepod.and.homepodmini.fill
hifispeaker.and.homepodmini
hifispeaker.and.homepodmini.fill
homepod
homepod.fill
homepod.2
homepod.2.fill
hifispeaker.and.homepod
hifispeaker.and.homepod.fill
hifispeaker
hifispeaker.fill
hifispeaker.2
hifispeaker.2.fill
appletv
appletv.fill
homepod.and.appletv
homepod.and.appletv.fill
homepodmini.and.appletv
homepodmini.and.appletv.fill
hifispeaker.and.appletv
hifispeaker.and.appletv.fill
appletvremote.gen1
appletvremote.gen1.fill
appletvremote.gen2
appletvremote.gen2.fill
appletvremote.gen3
appletvremote.gen3.fill
appletvremote.gen4
appletvremote.gen4.fill
magsafe.batterypack
magsafe.batterypack.fill
mediastick
cable.connector
cable.connector.horizontal
radio
radio.fill
tv
tv.fill
tv.inset.filled
tv.circle
tv.circle.fill
sparkles.tv
sparkles.tv.fill
4k.tv
4k.tv.fill
music.note.tv
music.note.tv.fill
play.tv
play.tv.fill
photo.tv
tv.and.hifispeaker.fill
tv.and.mediabox
airplayvideo
airplayvideo.circle
airplayvideo.circle.fill
airplayvideo.badge.exclamationmark
airplayaudio
airplayaudio.circle
airplayaudio.circle.fill
airplayaudio.badge.exclamationmark
dot.radiowaves.left.and.right
dot.radiowaves.right
dot.radiowaves.forward
wave.3.left
wave.3.left.circle
wave.3.left.circle.fill
wave.3.backward
wave.3.backward.circle
wave.3.backward.circle.fill
wave.3.right
wave.3.right.circle
wave.3.right.circle.fill
wave.3.forward
wave.3.forward.circle
wave.3.forward.circle.fill
dot.radiowaves.up.forward
antenna.radiowaves.left.and.right
antenna.radiowaves.left.and.right.slash
antenna.radiowaves.left.and.right.circle
antenna.radiowaves.left.and.right.circle.fill
pip
pip.fill
pip.exit
pip.enter
pip.swap
pip.remove
rectangle.arrowtriangle.2.outward
rectangle.arrowtriangle.2.inward
rectangle.portrait.arrowtriangle.2.outward
rectangle.portrait.arrowtriangle.2.inward
rectangle.2.swap
guitars
guitars.fill
airplane
airplane.circle
airplane.circle.fill
airplane.arrival
airplane.departure
car
car.fill
car.circle
car.circle.fill
bolt.car
bolt.car.fill
bolt.car.circle
bolt.car.circle.fill
car.2
car.2.fill
bus
bus.fill
bus.doubledecker
bus.doubledecker.fill
tram
tram.fill
tram.circle
tram.circle.fill
tram.fill.tunnel
cablecar
cablecar.fill
ferry
ferry.fill
car.ferry
car.ferry.fill
train.side.front.car
train.side.middle.car
train.side.rear.car
bicycle
bicycle.circle
bicycle.circle.fill
scooter
parkingsign
parkingsign.circle
parkingsign.circle.fill
fuelpump
fuelpump.fill
fuelpump.circle
fuelpump.circle.fill
fanblades
fanblades.fill
bed.double
bed.double.fill
bed.double.circle
bed.double.circle.fill
lungs
lungs.fill
allergens
pills
pills.fill
pills.circle
pills.circle.fill
testtube.2
ivfluid.bag
ivfluid.bag.fill
cross.vial
cross.vial.fill
cross
cross.fill
cross.circle
cross.circle.fill
hare
hare.fill
tortoise
tortoise.fill
pawprint
pawprint.fill
pawprint.circle
pawprint.circle.fill
ant
ant.fill
ant.circle
ant.circle.fill
ladybug
ladybug.fill
leaf
leaf.fill
leaf.circle
leaf.circle.fill
leaf.arrow.triangle.circlepath
film
film.fill
film.circle
film.circle.fill
sportscourt
sportscourt.fill
face.smiling
face.smiling.fill
face.dashed
face.dashed.fill
crown
crown.fill
comb
comb.fill
qrcode
barcode
viewfinder
viewfinder.circle
viewfinder.circle.fill
barcode.viewfinder
qrcode.viewfinder
plus.viewfinder
camera.viewfinder
faceid
doc.viewfinder
doc.viewfinder.fill
location.viewfinder
location.fill.viewfinder
person.fill.viewfinder
text.viewfinder
dot.viewfinder
dot.circle.viewfinder
photo
photo.fill
photo.circle
photo.circle.fill
text.below.photo
text.below.photo.fill
checkerboard.rectangle
camera.metering.center.weighted.average
camera.metering.center.weighted
camera.metering.matrix
camera.metering.multispot
camera.metering.none
camera.metering.partial
camera.metering.spot
camera.metering.unknown
camera.aperture
rectangle.dashed
rectangle.dashed.badge.record
rectangle.badge.plus
rectangle.fill.badge.plus
rectangle.badge.minus
rectangle.fill.badge.minus
rectangle.badge.checkmark
rectangle.fill.badge.checkmark
rectangle.badge.xmark
rectangle.fill.badge.xmark
rectangle.badge.person.crop
rectangle.fill.badge.person.crop
photo.on.rectangle
photo.fill.on.rectangle.fill
rectangle.on.rectangle.angled
rectangle.fill.on.rectangle.angled.fill
photo.on.rectangle.angled
rectangle.stack
rectangle.stack.fill
rectangle.stack.badge.plus
rectangle.stack.fill.badge.plus
rectangle.stack.badge.minus
rectangle.stack.fill.badge.minus
rectangle.stack.badge.person.crop
rectangle.stack.badge.person.crop.fill
rectangle.stack.badge.play
rectangle.stack.badge.play.fill
sparkles.rectangle.stack
sparkles.rectangle.stack.fill
sidebar.left
sidebar.right
sidebar.leading
sidebar.trailing
sidebar.squares.left
sidebar.squares.right
sidebar.squares.leading
sidebar.squares.trailing
macwindow
macwindow.badge.plus
slider.horizontal.2.rectangle.and.arrow.triangle.2.circlepath
dock.rectangle
dock.arrow.up.rectangle
dock.arrow.down.rectangle
menubar.rectangle
menubar.dock.rectangle
menubar.dock.rectangle.badge.record
menubar.arrow.up.rectangle
menubar.arrow.down.rectangle
macwindow.on.rectangle
text.and.command.macwindow
keyboard.macwindow
uiwindow.split.2x1
mosaic
mosaic.fill
squares.below.rectangle
rectangle.split.3x3.fill
square.on.square.squareshape.controlhandles
squareshape.controlhandles.on.squareshape.controlhandles
pano
pano.fill
circle.grid.2x1
circle.grid.2x1.fill
circle.grid.2x1.left.filled
circle.grid.2x1.right.filled
square.and.line.vertical.and.square
square.fill.and.line.vertical.and.square.fill
square.filled.and.line.vertical.and.square
square.and.line.vertical.and.square.filled
flowchart
flowchart.fill
rectangle.connected.to.line.below
align.horizontal.left
align.horizontal.left.fill
align.horizontal.center
align.horizontal.center.fill
align.horizontal.right
align.horizontal.right.fill
align.vertical.top
align.vertical.top.fill
align.vertical.center
align.vertical.center.fill
align.vertical.bottom
align.vertical.bottom.fill
shield
shield.fill
shield.lefthalf.filled
shield.righthalf.filled
shield.slash
shield.slash.fill
shield.lefthalf.filled.slash
checkerboard.shield
switch.2
point.topleft.down.curvedto.point.bottomright.up
point.topleft.down.curvedto.point.bottomright.up.fill
point.topleft.down.curvedto.point.filled.bottomright.up
point.filled.topleft.down.curvedto.point.bottomright.up
app.connected.to.app.below.fill
slider.horizontal.3
slider.horizontal.below.rectangle
slider.horizontal.below.square.filled.and.square
slider.vertical.3
cube
cube.fill
cube.transparent
cube.transparent.fill
shippingbox
shippingbox.fill
shippingbox.circle
shippingbox.circle.fill
arkit
arkit.badge.xmark
cone
cone.fill
pyramid
pyramid.fill
square.stack.3d.down.right
square.stack.3d.down.right.fill
square.stack.3d.down.forward
square.stack.3d.down.forward.fill
square.stack.3d.up
square.stack.3d.up.fill
square.stack.3d.up.slash
square.stack.3d.up.slash.fill
square.stack.3d.up.badge.a
square.stack.3d.up.badge.a.fill
square.stack.3d.forward.dottedline
square.stack.3d.forward.dottedline.fill
livephoto
livephoto.slash
livephoto.badge.a
livephoto.play
scope
helm
clock
clock.fill
clock.circle
clock.circle.fill
clock.badge.checkmark
clock.badge.checkmark.fill
clock.badge.exclamationmark
clock.badge.exclamationmark.fill
deskclock
deskclock.fill
alarm
alarm.fill
stopwatch
stopwatch.fill
chart.xyaxis.line
timer
timer.square
clock.arrow.circlepath
exclamationmark.arrow.circlepath
clock.arrow.2.circlepath
gamecontroller
gamecontroller.fill
l.joystick
l.joystick.fill
r.joystick
r.joystick.fill
l.joystick.press.down
l.joystick.press.down.fill
r.joystick.press.down
r.joystick.press.down.fill
l.joystick.tilt.left
l.joystick.tilt.left.fill
l.joystick.tilt.right
l.joystick.tilt.right.fill
l.joystick.tilt.up
l.joystick.tilt.up.fill
l.joystick.tilt.down
l.joystick.tilt.down.fill
r.joystick.tilt.left
r.joystick.tilt.left.fill
r.joystick.tilt.right
r.joystick.tilt.right.fill
r.joystick.tilt.up
r.joystick.tilt.up.fill
r.joystick.tilt.down
r.joystick.tilt.down.fill
dpad
dpad.fill
dpad.left.filled
dpad.up.filled
dpad.right.filled
dpad.down.filled
circle.circle
circle.circle.fill
square.circle
square.circle.fill
triangle.circle
triangle.circle.fill
rectangle.roundedtop
rectangle.roundedtop.fill
rectangle.roundedbottom
rectangle.roundedbottom.fill
l.rectangle.roundedbottom
l.rectangle.roundedbottom.fill
l1.rectangle.roundedbottom
l1.rectangle.roundedbottom.fill
l2.rectangle.roundedtop
l2.rectangle.roundedtop.fill
r.rectangle.roundedbottom
r.rectangle.roundedbottom.fill
r1.rectangle.roundedbottom
r1.rectangle.roundedbottom.fill
r2.rectangle.roundedtop
r2.rectangle.roundedtop.fill
lb.rectangle.roundedbottom
lb.rectangle.roundedbottom.fill
rb.rectangle.roundedbottom
rb.rectangle.roundedbottom.fill
lt.rectangle.roundedtop
lt.rectangle.roundedtop.fill
rt.rectangle.roundedtop
rt.rectangle.roundedtop.fill
zl.rectangle.roundedtop
zl.rectangle.roundedtop.fill
zr.rectangle.roundedtop
zr.rectangle.roundedtop.fill
logo.playstation
logo.xbox
paintpalette
paintpalette.fill
cup.and.saucer
cup.and.saucer.fill
takeoutbag.and.cup.and.straw
takeoutbag.and.cup.and.straw.fill
fork.knife
fork.knife.circle
fork.knife.circle.fill
figure.walk
figure.walk.circle
figure.walk.circle.fill
figure.walk.diamond
figure.walk.diamond.fill
figure.stand
figure.stand.line.dotted.figure.stand
figure.wave
figure.wave.circle
figure.wave.circle.fill
figure.roll
ear
ear.badge.checkmark
ear.trianglebadge.exclamationmark
ear.and.waveform
ear.fill
hearingdevice.ear
hand.raised
hand.raised.fill
hand.raised.circle
hand.raised.circle.fill
hand.raised.square
hand.raised.square.fill
hand.raised.slash
hand.raised.slash.fill
hand.thumbsup
hand.thumbsup.fill
hand.thumbsup.circle
hand.thumbsup.circle.fill
hand.thumbsdown
hand.thumbsdown.fill
hand.thumbsdown.circle
hand.thumbsdown.circle.fill
hand.point.up.left
hand.point.up.left.fill
hand.draw
hand.draw.fill
hand.tap
hand.tap.fill
rectangle.and.hand.point.up.left
rectangle.and.hand.point.up.left.fill
rectangle.filled.and.hand.point.up.left
rectangle.and.hand.point.up.left.filled
hand.point.left
hand.point.left.fill
hand.point.right
hand.point.right.fill
hand.point.up
hand.point.up.fill
hand.point.up.braille
hand.point.up.braille.fill
hand.point.down
hand.point.down.fill
hand.wave
hand.wave.fill
hands.clap
hands.clap.fill
hands.sparkles
hands.sparkles.fill
rectangle.compress.vertical
rectangle.expand.vertical
rectangle.and.arrow.up.right.and.arrow.down.left
rectangle.and.arrow.up.right.and.arrow.down.left.slash
square.2.stack.3d
square.2.stack.3d.top.filled
square.2.stack.3d.bottom.filled
square.3.layers.3d.down.right
square.3.layers.3d.down.right.slash
square.3.layers.3d.down.left
square.3.layers.3d.down.left.slash
square.3.layers.3d.down.forward
square.3.layers.3d.down.backward
square.3.stack.3d
square.3.stack.3d.slash
square.3.stack.3d.top.filled
square.3.stack.3d.middle.filled
square.3.stack.3d.bottom.filled
cylinder
cylinder.fill
cylinder.split.1x2
cylinder.split.1x2.fill
chart.bar
chart.bar.fill
chart.pie
chart.pie.fill
chart.bar.xaxis
chart.line.uptrend.xyaxis
chart.line.uptrend.xyaxis.circle
chart.line.uptrend.xyaxis.circle.fill
dot.squareshape.split.2x2
squareshape.split.2x2.dotted
squareshape.split.2x2
squareshape.split.3x3
burst
burst.fill
waveform.path.ecg
waveform.path.ecg.rectangle
waveform.path.ecg.rectangle.fill
waveform.path
waveform.path.badge.plus
waveform.path.badge.minus
point.3.connected.trianglepath.dotted
point.3.filled.connected.trianglepath.dotted
waveform
waveform.circle
waveform.circle.fill
waveform.badge.plus
waveform.badge.minus
waveform.badge.exclamationmark
waveform.and.magnifyingglass
waveform.and.mic
staroflife
staroflife.fill
staroflife.circle
staroflife.circle.fill
simcard
simcard.fill
simcard.2
simcard.2.fill
sdcard
sdcard.fill
esim
esim.fill
touchid
bonjour
atom
scalemass
scalemass.fill
gift
gift.fill
gift.circle
gift.circle.fill
plus.app
plus.app.fill
arrow.down.app
arrow.down.app.fill
arrow.up.forward.app
arrow.up.forward.app.fill
xmark.app
xmark.app.fill
questionmark.app
questionmark.app.fill
app.badge
app.badge.fill
app.badge.checkmark
app.badge.checkmark.fill
app.dashed
questionmark.app.dashed
appclip
app.gift
app.gift.fill
studentdesk
hourglass
hourglass.circle
hourglass.circle.fill
hourglass.badge.plus
hourglass.bottomhalf.filled
hourglass.tophalf.filled
banknote
banknote.fill
paragraphsign
purchased
purchased.circle
purchased.circle.fill
perspective
circle.and.line.horizontal
circle.and.line.horizontal.fill
trapezoid.and.line.vertical
trapezoid.and.line.vertical.fill
trapezoid.and.line.horizontal
trapezoid.and.line.horizontal.fill
aspectratio
aspectratio.fill
camera.filters
skew
arrow.left.and.right.righttriangle.left.righttriangle.right
arrow.left.and.right.righttriangle.left.righttriangle.right.fill
arrow.up.and.down.righttriangle.up.righttriangle.down
arrow.up.and.down.righttriangle.up.righttriangle.down.fill
arrowtriangle.left.and.line.vertical.and.arrowtriangle.right
arrowtriangle.left.and.line.vertical.and.arrowtriangle.right.fill
arrowtriangle.right.and.line.vertical.and.arrowtriangle.left
arrowtriangle.right.and.line.vertical.and.arrowtriangle.left.fill
grid
grid.circle
grid.circle.fill
burn
lifepreserver
lifepreserver.fill
recordingtape
binoculars
binoculars.fill
battery.100
battery.75
battery.50
battery.25
battery.0
battery.100.bolt
minus.plus.batteryblock
minus.plus.batteryblock.fill
bolt.batteryblock
bolt.batteryblock.fill
lightbulb
lightbulb.fill
lightbulb.circle
lightbulb.circle.fill
lightbulb.slash
lightbulb.slash.fill
fibrechannel
checklist
square.fill.text.grid.1x2
list.dash
list.bullet
list.bullet.circle
list.bullet.circle.fill
list.triangle
list.bullet.indent
list.number
list.star
increase.indent
decrease.indent
decrease.quotelevel
increase.quotelevel
list.bullet.below.rectangle
text.badge.plus
text.badge.minus
text.badge.checkmark
text.badge.xmark
text.badge.star
text.insert
text.append
text.quote
text.alignleft
text.aligncenter
text.alignright
text.justify
text.justify.left
text.justify.right
text.justify.leading
text.justify.trailing
text.redaction
list.and.film
line.3.horizontal
line.3.horizontal.decrease
line.3.horizontal.decrease.circle
line.3.horizontal.decrease.circle.fill
line.3.horizontal.circle
line.3.horizontal.circle.fill
line.2.horizontal.decrease.circle
line.2.horizontal.decrease.circle.fill
character
textformat.size.smaller
textformat.size.larger
textformat.size
textformat
textformat.alt
textformat.superscript
textformat.subscript
abc
textformat.abc
textformat.abc.dottedunderline
bold
italic
underline
strikethrough
shadow
bold.italic.underline
bold.underline
view.2d
view.3d
character.cursor.ibeam
fx
f.cursive
f.cursive.circle
f.cursive.circle.fill
k
sum
percent
function
fn
textformat.123
123.rectangle
123.rectangle.fill
character.textbox
a.magnify
info
info.circle
info.circle.fill
at
at.circle
at.circle.fill
at.badge.plus
at.badge.minus
questionmark
questionmark.circle
questionmark.circle.fill
questionmark.square
questionmark.square.fill
questionmark.diamond
questionmark.diamond.fill
exclamationmark
exclamationmark.2
exclamationmark.3
exclamationmark.circle
exclamationmark.circle.fill
exclamationmark.square
exclamationmark.square.fill
exclamationmark.octagon
exclamationmark.octagon.fill
exclamationmark.shield
exclamationmark.shield.fill
plus
plus.circle
plus.circle.fill
plus.square
plus.square.fill
plus.rectangle
plus.rectangle.fill
plus.rectangle.portrait
plus.rectangle.portrait.fill
plus.diamond
plus.diamond.fill
minus
minus.circle
minus.circle.fill
minus.square
minus.square.fill
minus.rectangle
minus.rectangle.fill
minus.rectangle.portrait
minus.rectangle.portrait.fill
minus.diamond
minus.diamond.fill
plusminus
plusminus.circle
plusminus.circle.fill
plus.forwardslash.minus
minus.forwardslash.plus
multiply
multiply.circle
multiply.circle.fill
multiply.square
multiply.square.fill
xmark.rectangle
xmark.rectangle.fill
xmark.rectangle.portrait
xmark.rectangle.portrait.fill
xmark.diamond
xmark.diamond.fill
xmark.shield
xmark.shield.fill
xmark.octagon
xmark.octagon.fill
divide
divide.circle
divide.circle.fill
divide.square
divide.square.fill
equal
equal.circle
equal.circle.fill
equal.square
equal.square.fill
lessthan
lessthan.circle
lessthan.circle.fill
lessthan.square
lessthan.square.fill
greaterthan
greaterthan.circle
greaterthan.circle.fill
greaterthan.square
greaterthan.square.fill
chevron.left.forwardslash.chevron.right
parentheses
curlybraces
curlybraces.square
curlybraces.square.fill
ellipsis.curlybraces
number
number.circle
number.circle.fill
number.square
number.square.fill
x.squareroot
xmark
xmark.circle
xmark.circle.fill
xmark.square
xmark.square.fill
checkmark
checkmark.circle
checkmark.circle.fill
checkmark.circle.trianglebadge.exclamationmark
checkmark.square
checkmark.square.fill
checkmark.rectangle
checkmark.rectangle.fill
checkmark.rectangle.portrait
checkmark.rectangle.portrait.fill
checkmark.diamond
checkmark.diamond.fill
checkmark.shield
checkmark.shield.fill
chevron.left
chevron.left.circle
chevron.left.circle.fill
chevron.left.square
chevron.left.square.fill
chevron.backward
chevron.backward.circle
chevron.backward.circle.fill
chevron.backward.square
chevron.backward.square.fill
chevron.right
chevron.right.circle
chevron.right.circle.fill
chevron.right.square
chevron.right.square.fill
chevron.forward
chevron.forward.circle
chevron.forward.circle.fill
chevron.forward.square
chevron.forward.square.fill
chevron.left.2
chevron.backward.2
chevron.right.2
chevron.forward.2
chevron.up
chevron.up.circle
chevron.up.circle.fill
chevron.up.square
chevron.up.square.fill
chevron.down
chevron.down.circle
chevron.down.circle.fill
chevron.down.square
chevron.down.square.fill
control
projective
chevron.up.chevron.down
chevron.compact.up
chevron.compact.down
chevron.compact.left
chevron.compact.right
arrow.left
arrow.left.circle
arrow.left.circle.fill
arrow.left.square
arrow.left.square.fill
arrow.backward
arrow.backward.circle
arrow.backward.circle.fill
arrow.backward.square
arrow.backward.square.fill
arrow.right
arrow.right.circle
arrow.right.circle.fill
arrow.right.square
arrow.right.square.fill
arrow.forward
arrow.forward.circle
arrow.forward.circle.fill
arrow.forward.square
arrow.forward.square.fill
arrow.up
arrow.up.circle
arrow.up.circle.fill
arrow.up.square
arrow.up.square.fill
arrow.down
arrow.down.circle
arrow.down.circle.fill
arrow.down.square
arrow.down.square.fill
arrow.up.left
arrow.up.left.circle
arrow.up.left.circle.fill
arrow.up.left.square
arrow.up.left.square.fill
arrow.up.backward
arrow.up.backward.circle
arrow.up.backward.circle.fill
arrow.up.backward.square
arrow.up.backward.square.fill
arrow.up.right
arrow.up.right.circle
arrow.up.right.circle.fill
arrow.up.right.square
arrow.up.right.square.fill
arrow.up.forward
arrow.up.forward.circle
arrow.up.forward.circle.fill
arrow.up.forward.square
arrow.up.forward.square.fill
arrow.down.left
arrow.down.left.circle
arrow.down.left.circle.fill
arrow.down.left.square
arrow.down.left.square.fill
arrow.down.backward
arrow.down.backward.circle
arrow.down.backward.circle.fill
arrow.down.backward.square
arrow.down.backward.square.fill
arrow.down.right
arrow.down.right.circle
arrow.down.right.circle.fill
arrow.down.right.square
arrow.down.right.square.fill
arrow.down.forward
arrow.down.forward.circle
arrow.down.forward.circle.fill
arrow.down.forward.square
arrow.down.forward.square.fill
arrow.left.arrow.right
arrow.left.arrow.right.circle
arrow.left.arrow.right.circle.fill
arrow.left.arrow.right.square
arrow.left.arrow.right.square.fill
arrow.up.arrow.down
arrow.up.arrow.down.circle
arrow.up.arrow.down.circle.fill
arrow.up.arrow.down.square
arrow.up.arrow.down.square.fill
arrow.turn.down.left
arrow.turn.up.left
arrow.turn.down.right
arrow.turn.up.right
arrow.turn.right.up
arrow.turn.left.up
arrow.turn.right.down
arrow.turn.left.down
arrow.uturn.left
arrow.uturn.left.circle
arrow.uturn.left.circle.fill
arrow.uturn.left.circle.badge.ellipsis
arrow.uturn.left.square
arrow.uturn.left.square.fill
arrow.uturn.backward
arrow.uturn.backward.circle
arrow.uturn.backward.circle.fill
arrow.uturn.backward.circle.badge.ellipsis
arrow.uturn.backward.square
arrow.uturn.backward.square.fill
arrow.uturn.right
arrow.uturn.right.circle
arrow.uturn.right.circle.fill
arrow.uturn.right.square
arrow.uturn.right.square.fill
arrow.uturn.forward
arrow.uturn.forward.circle
arrow.uturn.forward.circle.fill
arrow.uturn.forward.square
arrow.uturn.forward.square.fill
arrow.uturn.up
arrow.uturn.up.circle
arrow.uturn.up.circle.fill
arrow.uturn.up.square
arrow.uturn.up.square.fill
arrow.uturn.down
arrow.uturn.down.circle
arrow.uturn.down.circle.fill
arrow.uturn.down.square
arrow.uturn.down.square.fill
arrow.up.and.down.and.arrow.left.and.right
arrow.up.left.and.down.right.and.arrow.up.right.and.down.left
arrow.left.and.right
arrow.left.and.right.circle
arrow.left.and.right.circle.fill
arrow.left.and.right.square
arrow.left.and.right.square.fill
arrow.up.and.down
arrow.up.and.down.circle
arrow.up.and.down.circle.fill
arrow.up.and.down.square
arrow.up.and.down.square.fill
arrow.up.to.line
arrow.up.to.line.compact
arrow.up.to.line.circle
arrow.up.to.line.circle.fill
arrow.down.to.line
arrow.down.to.line.compact
arrow.down.to.line.circle
arrow.down.to.line.circle.fill
arrow.left.to.line
arrow.left.to.line.compact
arrow.left.to.line.circle
arrow.left.to.line.circle.fill
arrow.backward.to.line
arrow.backward.to.line.circle
arrow.backward.to.line.circle.fill
arrow.right.to.line
arrow.right.to.line.compact
arrow.right.to.line.circle
arrow.right.to.line.circle.fill
arrow.forward.to.line
arrow.forward.to.line.circle
arrow.forward.to.line.circle.fill
arrow.clockwise
arrow.clockwise.circle
arrow.clockwise.circle.fill
arrow.counterclockwise
arrow.counterclockwise.circle
arrow.counterclockwise.circle.fill
arrow.up.left.and.arrow.down.right
arrow.up.left.and.arrow.down.right.circle
arrow.up.left.and.arrow.down.right.circle.fill
arrow.up.backward.and.arrow.down.forward
arrow.up.backward.and.arrow.down.forward.circle
arrow.up.backward.and.arrow.down.forward.circle.fill
arrow.down.right.and.arrow.up.left
arrow.down.right.and.arrow.up.left.circle
arrow.down.right.and.arrow.up.left.circle.fill
arrow.down.forward.and.arrow.up.backward
arrow.down.forward.and.arrow.up.backward.circle
arrow.down.forward.and.arrow.up.backward.circle.fill
return
return.left
return.right
arrow.2.squarepath
arrow.triangle.2.circlepath
arrow.triangle.2.circlepath.circle
arrow.triangle.2.circlepath.circle.fill
exclamationmark.arrow.triangle.2.circlepath
arrow.triangle.capsulepath
arrow.3.trianglepath
arrow.triangle.turn.up.right.diamond
arrow.triangle.turn.up.right.diamond.fill
arrow.triangle.turn.up.right.circle
arrow.triangle.turn.up.right.circle.fill
arrow.triangle.merge
arrow.triangle.swap
arrow.triangle.branch
arrow.triangle.pull
arrowtriangle.left
arrowtriangle.left.fill
arrowtriangle.left.circle
arrowtriangle.left.circle.fill
arrowtriangle.left.square
arrowtriangle.left.square.fill
arrowtriangle.backward
arrowtriangle.backward.fill
arrowtriangle.backward.circle
arrowtriangle.backward.circle.fill
arrowtriangle.backward.square
arrowtriangle.backward.square.fill
arrowtriangle.right
arrowtriangle.right.fill
arrowtriangle.right.circle
arrowtriangle.right.circle.fill
arrowtriangle.right.square
arrowtriangle.right.square.fill
arrowtriangle.forward
arrowtriangle.forward.fill
arrowtriangle.forward.circle
arrowtriangle.forward.circle.fill
arrowtriangle.forward.square
arrowtriangle.forward.square.fill
arrowtriangle.up
arrowtriangle.up.fill
arrowtriangle.up.circle
arrowtriangle.up.circle.fill
arrowtriangle.up.square
arrowtriangle.up.square.fill
arrowtriangle.down
arrowtriangle.down.fill
arrowtriangle.down.circle
arrowtriangle.down.circle.fill
arrowtriangle.down.square
arrowtriangle.down.square.fill
slash.circle
slash.circle.fill
asterisk
asterisk.circle
asterisk.circle.fill
a.circle
a.circle.fill
a.square
a.square.fill
b.circle
b.circle.fill
b.square
b.square.fill
c.circle
c.circle.fill
c.square
c.square.fill
d.circle
d.circle.fill
d.square
d.square.fill
e.circle
e.circle.fill
e.square
e.square.fill
f.circle
f.circle.fill
f.square
f.square.fill
g.circle
g.circle.fill
g.square
g.square.fill
h.circle
h.circle.fill
h.square
h.square.fill
i.circle
i.circle.fill
i.square
i.square.fill
j.circle
j.circle.fill
j.square
j.square.fill
k.circle
k.circle.fill
k.square
k.square.fill
l.circle
l.circle.fill
l.square
l.square.fill
m.circle
m.circle.fill
m.square
m.square.fill
n.circle
n.circle.fill
n.square
n.square.fill
o.circle
o.circle.fill
o.square
o.square.fill
p.circle
p.circle.fill
p.square
p.square.fill
q.circle
q.circle.fill
q.square
q.square.fill
r.circle
r.circle.fill
r.square
r.square.fill
s.circle
s.circle.fill
s.square
s.square.fill
t.circle
t.circle.fill
t.square
t.square.fill
u.circle
u.circle.fill
u.square
u.square.fill
v.circle
v.circle.fill
v.square
v.square.fill
w.circle
w.circle.fill
w.square
w.square.fill
x.circle
x.circle.fill
x.square
x.square.fill
y.circle
y.circle.fill
y.square
y.square.fill
z.circle
z.circle.fill
z.square
z.square.fill
dollarsign.circle
dollarsign.circle.fill
dollarsign.square
dollarsign.square.fill
centsign.circle
centsign.circle.fill
centsign.square
centsign.square.fill
yensign.circle
yensign.circle.fill
yensign.square
yensign.square.fill
sterlingsign.circle
sterlingsign.circle.fill
sterlingsign.square
sterlingsign.square.fill
francsign.circle
francsign.circle.fill
francsign.square
francsign.square.fill
florinsign.circle
florinsign.circle.fill
florinsign.square
florinsign.square.fill
turkishlirasign.circle
turkishlirasign.circle.fill
turkishlirasign.square
turkishlirasign.square.fill
rublesign.circle
rublesign.circle.fill
rublesign.square
rublesign.square.fill
eurosign.circle
eurosign.circle.fill
eurosign.square
eurosign.square.fill
dongsign.circle
dongsign.circle.fill
dongsign.square
dongsign.square.fill
indianrupeesign.circle
indianrupeesign.circle.fill
indianrupeesign.square
indianrupeesign.square.fill
tengesign.circle
tengesign.circle.fill
tengesign.square
tengesign.square.fill
pesetasign.circle
pesetasign.circle.fill
pesetasign.square
pesetasign.square.fill
pesosign.circle
pesosign.circle.fill
pesosign.square
pesosign.square.fill
kipsign.circle
kipsign.circle.fill
kipsign.square
kipsign.square.fill
wonsign.circle
wonsign.circle.fill
wonsign.square
wonsign.square.fill
lirasign.circle
lirasign.circle.fill
lirasign.square
lirasign.square.fill
australsign.circle
australsign.circle.fill
australsign.square
australsign.square.fill
hryvniasign.circle
hryvniasign.circle.fill
hryvniasign.square
hryvniasign.square.fill
nairasign.circle
nairasign.circle.fill
nairasign.square
nairasign.square.fill
guaranisign.circle
guaranisign.circle.fill
guaranisign.square
guaranisign.square.fill
coloncurrencysign.circle
coloncurrencysign.circle.fill
coloncurrencysign.square
coloncurrencysign.square.fill
cedisign.circle
cedisign.circle.fill
cedisign.square
cedisign.square.fill
cruzeirosign.circle
cruzeirosign.circle.fill
cruzeirosign.square
cruzeirosign.square.fill
tugriksign.circle
tugriksign.circle.fill
tugriksign.square
tugriksign.square.fill
millsign.circle
millsign.circle.fill
millsign.square
millsign.square.fill
shekelsign.circle
shekelsign.circle.fill
shekelsign.square
shekelsign.square.fill
manatsign.circle
manatsign.circle.fill
manatsign.square
manatsign.square.fill
rupeesign.circle
rupeesign.circle.fill
rupeesign.square
rupeesign.square.fill
bahtsign.circle
bahtsign.circle.fill
bahtsign.square
bahtsign.square.fill
larisign.circle
larisign.circle.fill
larisign.square
larisign.square.fill
bitcoinsign.circle
bitcoinsign.circle.fill
bitcoinsign.square
bitcoinsign.square.fill
brazilianrealsign.circle
brazilianrealsign.circle.fill
brazilianrealsign.square
brazilianrealsign.square.fill
0.circle
0.circle.fill
0.square
0.square.fill
1.circle
1.circle.fill
1.square
1.square.fill
2.circle
2.circle.fill
2.square
2.square.fill
3.circle
3.circle.fill
3.square
3.square.fill
4.circle
4.circle.fill
4.square
4.square.fill
4.alt.circle
4.alt.circle.fill
4.alt.square
4.alt.square.fill
5.circle
5.circle.fill
5.square
5.square.fill
6.circle
6.circle.fill
6.square
6.square.fill
6.alt.circle
6.alt.circle.fill
6.alt.square
6.alt.square.fill
7.circle
7.circle.fill
7.square
7.square.fill
8.circle
8.circle.fill
8.square
8.square.fill
9.circle
9.circle.fill
9.square
9.square.fill
9.alt.circle
9.alt.circle.fill
9.alt.square
9.alt.square.fill
00.circle
00.circle.fill
00.square
00.square.fill
01.circle
01.circle.fill
01.square
01.square.fill
02.circle
02.circle.fill
02.square
02.square.fill
03.circle
03.circle.fill
03.square
03.square.fill
04.circle
04.circle.fill
04.square
04.square.fill
05.circle
05.circle.fill
05.square
05.square.fill
06.circle
06.circle.fill
06.square
06.square.fill
07.circle
07.circle.fill
07.square
07.square.fill
08.circle
08.circle.fill
08.square
08.square.fill
09.circle
09.circle.fill
09.square
09.square.fill
10.circle
10.circle.fill
10.square
10.square.fill
11.circle
11.circle.fill
11.square
11.square.fill
12.circle
12.circle.fill
12.square
12.square.fill
13.circle
13.circle.fill
13.square
13.square.fill
14.circle
14.circle.fill
14.square
14.square.fill
15.circle
15.circle.fill
15.square
15.square.fill
16.circle
16.circle.fill
16.square
16.square.fill
17.circle
17.circle.fill
17.square
17.square.fill
18.circle
18.circle.fill
18.square
18.square.fill
19.circle
19.circle.fill
19.square
19.square.fill
20.circle
20.circle.fill
20.square
20.square.fill
21.circle
21.circle.fill
21.square
21.square.fill
22.circle
22.circle.fill
22.square
22.square.fill
23.circle
23.circle.fill
23.square
23.square.fill
24.circle
24.circle.fill
24.square
24.square.fill
25.circle
25.circle.fill
25.square
25.square.fill
26.circle
26.circle.fill
26.square
26.square.fill
27.circle
27.circle.fill
27.square
27.square.fill
28.circle
28.circle.fill
28.square
28.square.fill
29.circle
29.circle.fill
29.square
29.square.fill
30.circle
30.circle.fill
30.square
30.square.fill
31.circle
31.circle.fill
31.square
31.square.fill
32.circle
32.circle.fill
32.square
32.square.fill
33.circle
33.circle.fill
33.square
33.square.fill
34.circle
34.circle.fill
34.square
34.square.fill
35.circle
35.circle.fill
35.square
35.square.fill
36.circle
36.circle.fill
36.square
36.square.fill
37.circle
37.circle.fill
37.square
37.square.fill
38.circle
38.circle.fill
38.square
38.square.fill
39.circle
39.circle.fill
39.square
39.square.fill
40.circle
40.circle.fill
40.square
40.square.fill
41.circle
41.circle.fill
41.square
41.square.fill
42.circle
42.circle.fill
42.square
42.square.fill
43.circle
43.circle.fill
43.square
43.square.fill
44.circle
44.circle.fill
44.square
44.square.fill
45.circle
45.circle.fill
45.square
45.square.fill
46.circle
46.circle.fill
46.square
46.square.fill
47.circle
47.circle.fill
47.square
47.square.fill
48.circle
48.circle.fill
48.square
48.square.fill
49.circle
49.circle.fill
49.square
49.square.fill
50.circle
50.circle.fill
50.square
50.square.fill
applelogo
================================================
FILE: External/SymbolPicker/Sources/SymbolPicker/Resources/zh_CN.lproj/Localizable.strings
================================================
"search_placeholder" = "搜索";
"cancel" = "取消";
"sf_symbol_picker" = "选择符号";
"done" = "确定";
================================================
FILE: External/SymbolPicker/Sources/SymbolPicker/SymbolPicker.swift
================================================
//
// SymbolPicker.swift
// SymbolPicker
//
// Created by Yubo Qin on 2/14/22.
//
import SwiftUI
#if os(macOS)
import AppKit
typealias PlatformColor = NSColor
#else
import UIKit
typealias PlatformColor = UIColor
#endif
public struct SymbolPicker: View {
// MARK: - Static consts
private static let symbols: [String] = {
guard let path = Bundle.module.path(forResource: "sfsymbols", ofType: "txt"),
let content = try? String(contentsOfFile: path)
else {
return []
}
return content
.split(separator: "\n")
.map { String($0) }
}()
private static var gridDimension: CGFloat {
#if os(iOS)
return 64
#elseif os(tvOS)
return 128
#elseif os(macOS)
return 30
#else
return 48
#endif
}
private static var symbolSize: CGFloat {
#if os(iOS)
return 24
#elseif os(tvOS)
return 48
#elseif os(macOS)
return 14
#else
return 24
#endif
}
private static var symbolCornerRadius: CGFloat {
#if os(iOS)
return 8
#elseif os(tvOS)
return 12
#elseif os(macOS)
return 4
#else
return 8
#endif
}
private static var systemGray5: Color {
dynamicColor(
light: .init(red: 0.9, green: 0.9, blue: 0.92, alpha: 1.0),
dark: .init(red: 0.17, green: 0.17, blue: 0.18, alpha: 1.0)
)
}
private static var systemBackground: Color {
dynamicColor(
light: .init(red: 1, green: 1, blue: 1, alpha: 1.0),
dark: .init(red: 0, green: 0, blue: 0, alpha: 1.0)
)
}
private static var secondarySystemBackground: Color {
dynamicColor(
light: .init(red: 0.95, green: 0.95, blue: 1, alpha: 1.0),
dark: .init(red: 0, green: 0, blue: 0, alpha: 1.0)
)
}
// MARK: - Properties
@Binding public var symbol: String
@State private var searchText = ""
@Environment(\.presentationMode) private var presentationMode
// MARK: - Public Init
public init(symbol: Binding) {
_symbol = symbol
}
// MARK: - View Components
@ViewBuilder
private var searchableSymbolGrid: some View {
#if os(iOS)
if #available(iOS 15.0, *) {
symbolGrid
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always))
} else {
VStack {
TextField(LocalizedString("search_placeholder"), text: $searchText)
.padding(8)
.padding(.horizontal, 8)
.background(Self.systemGray5)
.cornerRadius(8.0)
.padding(.horizontal, 16.0)
.autocapitalization(.none)
.disableAutocorrection(true)
symbolGrid
.padding()
}
}
#elseif os(tvOS)
symbolGrid
.searchable(text: $searchText, placement: .automatic)
#elseif os(macOS)
VStack(spacing: 10) {
TextField(LocalizedString("search_placeholder"), text: $searchText)
.disableAutocorrection(true)
symbolGrid
}
#else
symbolGrid
.searchable(text: $searchText, placement: .automatic)
#endif
}
private var symbolGrid: some View {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: Self.gridDimension, maximum: Self.gridDimension))]) {
ForEach(Self.symbols.filter { searchText.isEmpty ? true : $0.localizedCaseInsensitiveContains(searchText) }, id: \.self) { thisSymbol in
Button(action: {
symbol = thisSymbol
// Dismiss sheet. macOS will have done button
#if !os(macOS)
presentationMode.wrappedValue.dismiss()
#endif
}) {
if thisSymbol == symbol {
Image(systemName: thisSymbol)
.font(.system(size: Self.symbolSize))
.frame(maxWidth: .infinity, minHeight: Self.gridDimension)
#if !os(tvOS)
.background(Color.accentColor)
#else
.background(Color.gray.opacity(0.3))
#endif
.cornerRadius(Self.symbolCornerRadius)
.foregroundColor(.white)
} else {
Image(systemName: thisSymbol)
.font(.system(size: Self.symbolSize))
.frame(maxWidth: .infinity, minHeight: Self.gridDimension)
.background(Self.systemBackground)
.cornerRadius(Self.symbolCornerRadius)
.foregroundColor(.primary)
}
}
.buttonStyle(PlainButtonStyle())
}
}
}
}
public var body: some View {
#if !os(macOS)
NavigationView {
ZStack {
Self.secondarySystemBackground.edgesIgnoringSafeArea(.all)
searchableSymbolGrid
}
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(LocalizedString("cancel")) {
presentationMode.wrappedValue.dismiss()
}
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
#else
VStack(alignment: .leading, spacing: 10) {
Text(LocalizedString("sf_symbol_picker"))
.font(.headline)
Divider()
searchableSymbolGrid
.frame(maxWidth: .infinity, maxHeight: .infinity)
Divider()
HStack {
Button {
symbol = ""
presentationMode.wrappedValue.dismiss()
} label: {
Text(LocalizedString("cancel"))
}
.keyboardShortcut(.cancelAction)
Spacer()
Button {
presentationMode.wrappedValue.dismiss()
} label: {
Text(LocalizedString("done"))
}
}
}
.padding()
.frame(width: 520, height: 300, alignment: .center)
#endif
}
// MARK: - Private helpers
private static func dynamicColor(light: PlatformColor, dark: PlatformColor) -> Color {
#if os(iOS)
let color = PlatformColor { $0.userInterfaceStyle == .dark ? dark : light }
if #available(iOS 15.0, *) {
return Color(uiColor: color)
} else {
return Color(color)
}
#elseif os(tvOS)
let color = PlatformColor { $0.userInterfaceStyle == .dark ? dark : light }
return Color(uiColor: color)
#elseif os(macOS)
let color = PlatformColor(name: nil) { $0.name == .darkAqua ? dark : light }
if #available(macOS 12.0, *) {
return Color(nsColor: color)
} else {
return Color(color)
}
#else
return Color(uiColor: dark)
#endif
}
}
private func LocalizedString(_ key: String) -> String {
NSLocalizedString(key, bundle: .module, comment: "")
}
struct SymbolPicker_Previews: PreviewProvider {
@State static var symbol: String = "square.and.arrow.up"
static var previews: some View {
Group {
SymbolPicker(symbol: Self.$symbol)
SymbolPicker(symbol: Self.$symbol)
.preferredColorScheme(.dark)
}
}
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 Lakr Aream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# ActionBee
ActionBee is a programmable pasteboard action trigger.


## Preview Video
It can be used to clean your URL in text. To see code or import this module, check out [here](./Resources/ModuleSample/Module%20Export%20-%20Link%20Cleaner/).

With Universal Control and iCloud Pasteboard, link cleaner will work across devices.

It can also be used to run the formator as follows. To see code or import this module, check out [here](./Resources/ModuleSample/Module%20Export%20-%20Multiline%20Init%20Formatter/).

## Action Module
We encourage you to develop an action module yourself. To see how a module gets to work, create one and check out the source. It is well documented inside the code.
Generically speaking, we pass your pasteboard data in the process's environment and spawn your module that is compiled as binary. At the end, we read back a recipe from stdout where you can define what to do.
## Warning
This app itself does not require access to your data or an internet connection, but the module you install may do. We do **not** use any sandbox to protect your data or privacy. **Only import modules come with source code and exam each line yourself before compiling or executing them.**
## Contributor
Made with love by [@Lakr233](https://twitter.com/@Lakr233), thanks to all my lovely friends for testing and being with me day and night.
## One More Thing
If you are looking for an Android alternative (which was made for cleaning URL), checkout [Tarnhelm](https://github.com/lz233/Tarnhelm) by [@lz__233](https://twitter.com/lz__233).
If you are looking for a great pasteboard manager, checkout [PasteNow](https://apps.apple.com/cn/app/pastenow-instant-clipboard/id1552536109) by [@tualatrix](https://twitter.com/tualatrix). I also recommend [Raycast](https://www.raycast.com/)'s built-in pasteboard manager if you are not a heavy user of it.
## License
Generically speaking, we do not hold responsibility for anything that happened on your computer, nor your data or privacy.
[License](./LICENSE)
---
Copyright © 2022 Lakr Aream. All Rights Reserved.
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Binary/CommandLineBridge/CommandLineBridge/main.swift
================================================
//
// main.swift
// CommandLineBridge
//
// Created by Lakr Aream on 2022/8/13.
//
import Communicator
import Definition
import Foundation
import Source
guard let data = Communicator.retrieveParentData() else {
fatalError("unable to receive argument data")
}
guard let argument = ArgumentData.retrieve(withData: data) else {
fatalError("unable to receive argument object")
}
private let defaultRecipe: RecipeData = .init(
postAction: .none,
postContent: "",
continueQueue: true
)
let completion: ((RecipeData?) -> Never) = { recipe in
guard let recipe = recipe else {
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
guard let recipeBase64String = recipe.compileBase64() else {
fatalError("failed to compile recipe data")
}
Communicator.sendRecipeDataAndExit(recipeBase64String)
fatalError("malformed program flow")
}
do {
try ActionBee.solutionMain(event: argument, completion: completion)
} catch {
print(error.localizedDescription)
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
CFRunLoopRun()
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
50307AB928A75EA500598724 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50307AB828A75EA500598724 /* main.swift */; };
50307AC128A8AF0E00598724 /* Communicator in Frameworks */ = {isa = PBXBuildFile; productRef = 50307AC028A8AF0E00598724 /* Communicator */; };
50628BD928A8AF7D00882579 /* Source in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BD828A8AF7D00882579 /* Source */; };
50628BDB28A8CD2300882579 /* Definition in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BDA28A8CD2300882579 /* Definition */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
50307AB328A75EA500598724 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
50307AB528A75EA500598724 /* CommandLineBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLineBridge; sourceTree = BUILT_PRODUCTS_DIR; };
50307AB828A75EA500598724 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50307AB228A75EA500598724 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50307AC128A8AF0E00598724 /* Communicator in Frameworks */,
50628BD928A8AF7D00882579 /* Source in Frameworks */,
50628BDB28A8CD2300882579 /* Definition in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50307AAC28A75EA500598724 = {
isa = PBXGroup;
children = (
50307AB728A75EA500598724 /* CommandLineBridge */,
50307AB628A75EA500598724 /* Products */,
50307ABF28A8AF0B00598724 /* Frameworks */,
);
sourceTree = "";
};
50307AB628A75EA500598724 /* Products */ = {
isa = PBXGroup;
children = (
50307AB528A75EA500598724 /* CommandLineBridge */,
);
name = Products;
sourceTree = "";
};
50307AB728A75EA500598724 /* CommandLineBridge */ = {
isa = PBXGroup;
children = (
50307AB828A75EA500598724 /* main.swift */,
);
path = CommandLineBridge;
sourceTree = "";
};
50307ABF28A8AF0B00598724 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50307AB428A75EA500598724 /* CommandLineBridge */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */;
buildPhases = (
50307AB128A75EA500598724 /* Sources */,
50307AB228A75EA500598724 /* Frameworks */,
50307AB328A75EA500598724 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = CommandLineBridge;
packageProductDependencies = (
50307AC028A8AF0E00598724 /* Communicator */,
50628BD828A8AF7D00882579 /* Source */,
50628BDA28A8CD2300882579 /* Definition */,
);
productName = CommandLineBridge;
productReference = 50307AB528A75EA500598724 /* CommandLineBridge */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50307AAD28A75EA500598724 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
50307AB428A75EA500598724 = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50307AAC28A75EA500598724;
productRefGroup = 50307AB628A75EA500598724 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50307AB428A75EA500598724 /* CommandLineBridge */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
50307AB128A75EA500598724 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50307AB928A75EA500598724 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50307ABA28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
50307ABB28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
50307ABD28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
50307ABE28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABA28A75EA500598724 /* Debug */,
50307ABB28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABD28A75EA500598724 /* Debug */,
50307ABE28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
50307AC028A8AF0E00598724 /* Communicator */ = {
isa = XCSwiftPackageProductDependency;
productName = Communicator;
};
50628BD828A8AF7D00882579 /* Source */ = {
isa = XCSwiftPackageProductDependency;
productName = Source;
};
50628BDA28A8CD2300882579 /* Definition */ = {
isa = XCSwiftPackageProductDependency;
productName = Definition;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50307AAD28A75EA500598724 /* Project object */;
}
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/xcshareddata/xcschemes/CommandLineBridge.xcscheme
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Communicator/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Communicator/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Communicator",
products: [
.library(name: "Communicator", targets: ["Communicator"]),
],
targets: [
.target(name: "Communicator", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Communicator/Sources/Communicator/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Communicator/Sources/Communicator/Communicator.m
================================================
//
// Communicator.m
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import "Communicator.h"
NSData *argumentData;
__attribute__((constructor)) void communicator_constructor(void) {
[[NSBundle.mainBundle infoDictionary] setValue: @{ @"NSAllowsArbitraryLoads" : @YES }
forKey:@"NSAppTransportSecurity"];
NSString *message = [NSProcessInfo.processInfo.environment valueForKey:@"Communicator_Message"];
if (message.length <= 0) { return; }
NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NULL];
if (data == NULL || data.length <= 0) { return; }
argumentData = data;
}
@implementation Communicator
+ (NSData*)retrieveParentData {
return argumentData;
}
+ (void)sendRecipeDataAndExit:(NSString*)base64String {
NSLog(@"\nActionBee-Result-Recipe://%@", base64String);
exit(0);
}
@end
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Communicator/Sources/Communicator/include/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Definition/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Definition/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Definition",
products: [
.library(name: "Definition", targets: ["Definition"]),
],
targets: [
.target(name: "Definition", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/Definition/Sources/Definition/Definition.swift
================================================
import Foundation
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
public struct ArgumentData: Codable {
public let focusAppID: String?
public let focusAppName: String?
public let pasteboardContent: String
public init(focusAppID: String?, focusAppName: String?, pasteboardContent: String) {
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> ArgumentData? {
try? decoder.decode(ArgumentData.self, from: data)
}
}
public struct RecipeData: Codable {
public let postAction: PostAction
public let postContent: String
public let continueQueue: Bool
public enum PostAction: String, Codable {
case overwrite
case speak
case none
}
public init(postAction: PostAction, postContent: String, continueQueue: Bool) {
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> Self? {
try? decoder.decode(Self.self, from: data)
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/compile.sh
================================================
#!/bin/bash
# this compiler script is designed to issue binary to ./.build/cli
set -e
cd "$(dirname "$0")"/../
echo "[*] starting build at $(pwd)..."
if [ ! -f .action ]; then
exit 1
fi
echo "[*] cleaning build..."
rm -rf .build || true
mkdir .build
echo "[*] looking for target binary..."
BUILT_PRODUCTS_DIR=$(
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
-showBuildSettings \
CODE_SIGNING_ALLOWED="NO" \
2>/dev/null | grep -m 1 "BUILT_PRODUCTS_DIR" | grep -oEi "\/.*"
)
BINARY_LOCATION="$BUILT_PRODUCTS_DIR/CommandLineBridge"
# remove the binary
rm -f "$BINARY_LOCATION" || true
echo "[*] building binary to $BUILT_PRODUCTS_DIR..."
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
CODE_SIGNING_ALLOWED="NO" \
1>/dev/null 2>/dev/null
# check if the binary exists
if [ ! -f "$BINARY_LOCATION" ]; then
echo "[E] failed to emit binary at $BINARY_LOCATION"
exit 1
fi
echo "[*] copying binary..."
cp "$BINARY_LOCATION" .build/cli
echo "[*] signing binary..."
chmod +x .build/cli
codesign -s - --deep --force .build/cli 1>/dev/null 2>/dev/null
echo "[+] completed compile"
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/.supplement/launch.sh
================================================
#!/bin/bash
set -e
cd "$(dirname "$0")"/../
.build/cli
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/App.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/Source/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/Source/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Source",
products: [
.library(name: "Source", targets: ["Source"]),
],
dependencies: [
.package(name: "Definition", path: "./.supplement/Definition"),
],
targets: [
.target(name: "Source", dependencies: ["Definition"]),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/Source/Sources/Source/CleanerRule/CleanerRule.swift
================================================
//
// DomainRule.swift
//
//
// Created by Lakr Aream on 2022/8/17.
//
import Foundation
let cleaners: [CleanerRule] = [
Twitter(),
BiliBili(), B23TV(),
]
protocol CleanerRule {
func isPotentialCandidate(original url: URL) -> Bool
func process(original url: URL) -> URL?
}
extension URL {
func deletingAllQueryParameters() -> URL? {
guard var components = URLComponents(
url: self,
resolvingAgainstBaseURL: false
) else {
return nil
}
components.queryItems = []
guard let newUrl = components.url else { return nil }
var str = newUrl.absoluteString
if str.hasSuffix("?") { str.removeLast() }
return URL(string: str)
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/Source/Sources/Source/CleanerRule/Rule+BiliBili.swift
================================================
//
// File.swift
//
//
// Created by Lakr Aream on 2022/8/18.
//
import Foundation
class BiliBili: CleanerRule {
func isPotentialCandidate(original url: URL) -> Bool {
url.host?.lowercased().contains("www.bilibili.com") ?? false
}
func process(original url: URL) -> URL? {
guard url.deletingLastPathComponent().lastPathComponent == "video",
let result = url.deletingAllQueryParameters()
else {
return nil
}
return result
}
}
class B23TV: CleanerRule {
func isPotentialCandidate(original url: URL) -> Bool {
url.host?.lowercased().contains("b23.tv") ?? false
}
func process(original url: URL) -> URL? {
var comps = URLComponents(url: url, resolvingAgainstBaseURL: false)
// comps?.scheme = "https"
guard let requestUrl = comps?.url else {
return nil
}
let sem = DispatchSemaphore(value: 0)
var cleanResult: URL?
DispatchQueue.global().async {
var request = URLRequest(
url: requestUrl,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 6
)
request.addValue(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
forHTTPHeaderField: "user-agent"
)
URLSession.shared.dataTask(with: request) { _, resp, _ in
defer { sem.signal() }
guard let resp = resp as? HTTPURLResponse else {
return
}
cleanResult = resp.url?.deletingAllQueryParameters()
}
.resume()
}
sem.wait()
return cleanResult
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/Source/Sources/Source/CleanerRule/Rule+Twitter.swift
================================================
//
// CleanerRule+Twitter.swift
//
//
// Created by Lakr Aream on 2022/8/17.
//
import Foundation
class Twitter: CleanerRule {
func isPotentialCandidate(original url: URL) -> Bool {
url.host?.lowercased().contains("twitter.com") ?? false
}
func process(original url: URL) -> URL? {
guard url.deletingLastPathComponent().lastPathComponent == "status",
let result = url.deletingAllQueryParameters()
else {
return nil
}
return result
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Link Cleaner/Source/Sources/Source/Source.swift
================================================
// ActionBee
//
// Executable Source Template - v1.0
//
import Definition
import Foundation
import Cocoa
public enum ActionBee {
public static func solutionMain(event: ArgumentData, completion: @escaping (RecipeData?) -> Never) throws {
let text = event.pasteboardContent
let types: NSTextCheckingResult.CheckingType = .link
let detector = try? NSDataDetector(types: types.rawValue)
guard let detect = detector else {
completion(.none)
}
let matches = detect.matches(
in: text,
options: .reportCompletion,
range: NSMakeRange(0, text.count)
)
var stringComps: [StringComps] = [
.init(isLink: false, messgae: "")
]
guard !matches.isEmpty else {
completion(.none)
}
// lazy man slow process but it works~
for idx in 0 ..< text.count {
let char = text[idx]
var isLink = false
for match in matches {
if match.range.contains(idx) {
isLink = true
break
}
}
if stringComps[stringComps.count - 1].isLink == isLink {
stringComps[stringComps.count - 1].messgae += String(char)
} else {
stringComps.append(.init(isLink: isLink, messgae: String(char)))
}
}
var processed = false
stringComps = stringComps.map { comps -> StringComps in
if !comps.isLink { return comps }
guard let url = URL(string: comps.messgae) else {
return comps
}
for cleaner in cleaners {
if cleaner.isPotentialCandidate(original: url),
let newUrl = cleaner.process(original: url)
{
processed = true
return .init(isLink: comps.isLink, messgae: newUrl.absoluteString)
}
}
return comps
}
let newText = stringComps
.map(\.messgae)
.joined()
guard processed else {
completion(.none)
}
let result = RecipeData(
postAction: .overwrite,
postContent: newText,
continueQueue: true
)
completion(result)
}
struct StringComps {
var isLink: Bool
var messgae: String
}
}
extension StringProtocol {
subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
subscript(range: Range) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
subscript(range: PartialRangeThrough) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
subscript(range: PartialRangeUpTo) -> SubSequence { self[.. Never) = { recipe in
guard let recipe = recipe else {
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
guard let recipeBase64String = recipe.compileBase64() else {
fatalError("failed to compile recipe data")
}
Communicator.sendRecipeDataAndExit(recipeBase64String)
fatalError("malformed program flow")
}
do {
try ActionBee.solutionMain(event: argument, completion: completion)
} catch {
print(error.localizedDescription)
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
CFRunLoopRun()
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
50307AB928A75EA500598724 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50307AB828A75EA500598724 /* main.swift */; };
50307AC128A8AF0E00598724 /* Communicator in Frameworks */ = {isa = PBXBuildFile; productRef = 50307AC028A8AF0E00598724 /* Communicator */; };
50628BD928A8AF7D00882579 /* Source in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BD828A8AF7D00882579 /* Source */; };
50628BDB28A8CD2300882579 /* Definition in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BDA28A8CD2300882579 /* Definition */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
50307AB328A75EA500598724 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
50307AB528A75EA500598724 /* CommandLineBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLineBridge; sourceTree = BUILT_PRODUCTS_DIR; };
50307AB828A75EA500598724 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50307AB228A75EA500598724 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50307AC128A8AF0E00598724 /* Communicator in Frameworks */,
50628BD928A8AF7D00882579 /* Source in Frameworks */,
50628BDB28A8CD2300882579 /* Definition in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50307AAC28A75EA500598724 = {
isa = PBXGroup;
children = (
50307AB728A75EA500598724 /* CommandLineBridge */,
50307AB628A75EA500598724 /* Products */,
50307ABF28A8AF0B00598724 /* Frameworks */,
);
sourceTree = "";
};
50307AB628A75EA500598724 /* Products */ = {
isa = PBXGroup;
children = (
50307AB528A75EA500598724 /* CommandLineBridge */,
);
name = Products;
sourceTree = "";
};
50307AB728A75EA500598724 /* CommandLineBridge */ = {
isa = PBXGroup;
children = (
50307AB828A75EA500598724 /* main.swift */,
);
path = CommandLineBridge;
sourceTree = "";
};
50307ABF28A8AF0B00598724 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50307AB428A75EA500598724 /* CommandLineBridge */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */;
buildPhases = (
50307AB128A75EA500598724 /* Sources */,
50307AB228A75EA500598724 /* Frameworks */,
50307AB328A75EA500598724 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = CommandLineBridge;
packageProductDependencies = (
50307AC028A8AF0E00598724 /* Communicator */,
50628BD828A8AF7D00882579 /* Source */,
50628BDA28A8CD2300882579 /* Definition */,
);
productName = CommandLineBridge;
productReference = 50307AB528A75EA500598724 /* CommandLineBridge */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50307AAD28A75EA500598724 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
50307AB428A75EA500598724 = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50307AAC28A75EA500598724;
productRefGroup = 50307AB628A75EA500598724 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50307AB428A75EA500598724 /* CommandLineBridge */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
50307AB128A75EA500598724 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50307AB928A75EA500598724 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50307ABA28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
50307ABB28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
50307ABD28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
50307ABE28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABA28A75EA500598724 /* Debug */,
50307ABB28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABD28A75EA500598724 /* Debug */,
50307ABE28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
50307AC028A8AF0E00598724 /* Communicator */ = {
isa = XCSwiftPackageProductDependency;
productName = Communicator;
};
50628BD828A8AF7D00882579 /* Source */ = {
isa = XCSwiftPackageProductDependency;
productName = Source;
};
50628BDA28A8CD2300882579 /* Definition */ = {
isa = XCSwiftPackageProductDependency;
productName = Definition;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50307AAD28A75EA500598724 /* Project object */;
}
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/xcshareddata/xcschemes/CommandLineBridge.xcscheme
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Communicator/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Communicator/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Communicator",
products: [
.library(name: "Communicator", targets: ["Communicator"]),
],
targets: [
.target(name: "Communicator", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Communicator/Sources/Communicator/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Communicator/Sources/Communicator/Communicator.m
================================================
//
// Communicator.m
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import "Communicator.h"
NSData *argumentData;
__attribute__((constructor)) void communicator_constructor(void) {
NSString *message = [NSProcessInfo.processInfo.environment valueForKey:@"Communicator_Message"];
if (message.length <= 0) { return; }
NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NULL];
if (data == NULL || data.length <= 0) { return; }
argumentData = data;
}
@implementation Communicator
+ (NSData*)retrieveParentData {
return argumentData;
}
+ (void)sendRecipeDataAndExit:(NSString*)base64String {
NSLog(@"\nActionBee-Result-Recipe://%@", base64String);
exit(0);
}
@end
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Communicator/Sources/Communicator/include/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Definition/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Definition/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Definition",
products: [
.library(name: "Definition", targets: ["Definition"]),
],
targets: [
.target(name: "Definition", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/Definition/Sources/Definition/Definition.swift
================================================
import Foundation
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
public struct ArgumentData: Codable {
public let focusAppID: String?
public let focusAppName: String?
public let pasteboardContent: String
public init(focusAppID: String?, focusAppName: String?, pasteboardContent: String) {
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> ArgumentData? {
try? decoder.decode(ArgumentData.self, from: data)
}
}
public struct RecipeData: Codable {
public let postAction: PostAction
public let postContent: String
public let continueQueue: Bool
public enum PostAction: String, Codable {
case overwrite
case speak
case none
}
public init(postAction: PostAction, postContent: String, continueQueue: Bool) {
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> Self? {
try? decoder.decode(Self.self, from: data)
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/compile.sh
================================================
#!/bin/bash
# this compiler script is designed to issue binary to ./.build/cli
set -e
cd "$(dirname "$0")"/../
echo "[*] starting build at $(pwd)..."
if [ ! -f .action ]; then
exit 1
fi
echo "[*] cleaning build..."
rm -rf .build || true
mkdir .build
echo "[*] looking for target binary..."
BUILT_PRODUCTS_DIR=$(
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
-showBuildSettings \
CODE_SIGNING_ALLOWED="NO" \
2>/dev/null | grep -m 1 "BUILT_PRODUCTS_DIR" | grep -oEi "\/.*"
)
BINARY_LOCATION="$BUILT_PRODUCTS_DIR/CommandLineBridge"
# remove the binary
rm -f "$BINARY_LOCATION" || true
echo "[*] building binary to $BUILT_PRODUCTS_DIR..."
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
CODE_SIGNING_ALLOWED="NO" \
1>/dev/null 2>/dev/null
# check if the binary exists
if [ ! -f "$BINARY_LOCATION" ]; then
echo "[E] failed to emit binary at $BINARY_LOCATION"
exit 1
fi
echo "[*] copying binary..."
cp "$BINARY_LOCATION" .build/cli
echo "[*] signing binary..."
chmod +x .build/cli
codesign -s - --deep --force .build/cli 1>/dev/null 2>/dev/null
echo "[+] completed compile"
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/.supplement/launch.sh
================================================
#!/bin/bash
set -e
cd "$(dirname "$0")"/../
.build/cli
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/App.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/Source/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/Source/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Source",
products: [
.library(name: "Source", targets: ["Source"]),
],
dependencies: [
.package(name: "Definition", path: "./.supplement/Definition"),
],
targets: [
.target(name: "Source", dependencies: ["Definition"]),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Multiline Init Formatter/Source/Sources/Source/Source.swift
================================================
// ActionBee
//
// Executable Source Template - v1.0
//
import Definition
import Foundation
/*
⚠️
Only changes within the current directory will be committed to the compiler,
other modifications outside Source dir will be ignored when build.
You can add any package dependencies in Package.swift, process your need, and
build us a recipe.
*/
public enum ActionBee {
public static func solutionMain(event: ArgumentData, completion: @escaping (RecipeData?) -> Never) throws {
guard event.pasteboardContent.hasPrefix("init("),
event.pasteboardContent.hasSuffix(")")
else {
completion(.none)
}
var payload = event.pasteboardContent
payload.removeFirst("init(".count)
payload.removeLast(")".count)
payload = payload
.components(separatedBy: ",")
.joined(separator: ",\n")
payload = "init(\n\(payload)\n)"
completion(RecipeData(
postAction: .overwrite,
postContent: payload,
continueQueue: false
))
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Binary/CommandLineBridge/CommandLineBridge/main.swift
================================================
//
// main.swift
// CommandLineBridge
//
// Created by Lakr Aream on 2022/8/13.
//
import Communicator
import Definition
import Foundation
import Source
guard let data = Communicator.retrieveParentData() else {
fatalError("unable to receive argument data")
}
guard let argument = ArgumentData.retrieve(withData: data) else {
fatalError("unable to receive argument object")
}
private let defaultRecipe: RecipeData = .init(
postAction: .none,
postContent: "",
continueQueue: true
)
let completion: ((RecipeData?) -> Never) = { recipe in
guard let recipe = recipe else {
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
guard let recipeBase64String = recipe.compileBase64() else {
fatalError("failed to compile recipe data")
}
Communicator.sendRecipeDataAndExit(recipeBase64String)
fatalError("malformed program flow")
}
do {
try ActionBee.solutionMain(event: argument, completion: completion)
} catch {
print(error.localizedDescription)
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
CFRunLoopRun()
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
50307AB928A75EA500598724 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50307AB828A75EA500598724 /* main.swift */; };
50307AC128A8AF0E00598724 /* Communicator in Frameworks */ = {isa = PBXBuildFile; productRef = 50307AC028A8AF0E00598724 /* Communicator */; };
50628BD928A8AF7D00882579 /* Source in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BD828A8AF7D00882579 /* Source */; };
50628BDB28A8CD2300882579 /* Definition in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BDA28A8CD2300882579 /* Definition */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
50307AB328A75EA500598724 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
50307AB528A75EA500598724 /* CommandLineBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLineBridge; sourceTree = BUILT_PRODUCTS_DIR; };
50307AB828A75EA500598724 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50307AB228A75EA500598724 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50307AC128A8AF0E00598724 /* Communicator in Frameworks */,
50628BD928A8AF7D00882579 /* Source in Frameworks */,
50628BDB28A8CD2300882579 /* Definition in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50307AAC28A75EA500598724 = {
isa = PBXGroup;
children = (
50307AB728A75EA500598724 /* CommandLineBridge */,
50307AB628A75EA500598724 /* Products */,
50307ABF28A8AF0B00598724 /* Frameworks */,
);
sourceTree = "";
};
50307AB628A75EA500598724 /* Products */ = {
isa = PBXGroup;
children = (
50307AB528A75EA500598724 /* CommandLineBridge */,
);
name = Products;
sourceTree = "";
};
50307AB728A75EA500598724 /* CommandLineBridge */ = {
isa = PBXGroup;
children = (
50307AB828A75EA500598724 /* main.swift */,
);
path = CommandLineBridge;
sourceTree = "";
};
50307ABF28A8AF0B00598724 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50307AB428A75EA500598724 /* CommandLineBridge */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */;
buildPhases = (
50307AB128A75EA500598724 /* Sources */,
50307AB228A75EA500598724 /* Frameworks */,
50307AB328A75EA500598724 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = CommandLineBridge;
packageProductDependencies = (
50307AC028A8AF0E00598724 /* Communicator */,
50628BD828A8AF7D00882579 /* Source */,
50628BDA28A8CD2300882579 /* Definition */,
);
productName = CommandLineBridge;
productReference = 50307AB528A75EA500598724 /* CommandLineBridge */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50307AAD28A75EA500598724 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
50307AB428A75EA500598724 = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50307AAC28A75EA500598724;
productRefGroup = 50307AB628A75EA500598724 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50307AB428A75EA500598724 /* CommandLineBridge */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
50307AB128A75EA500598724 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50307AB928A75EA500598724 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50307ABA28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
50307ABB28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
50307ABD28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
50307ABE28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABA28A75EA500598724 /* Debug */,
50307ABB28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABD28A75EA500598724 /* Debug */,
50307ABE28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
50307AC028A8AF0E00598724 /* Communicator */ = {
isa = XCSwiftPackageProductDependency;
productName = Communicator;
};
50628BD828A8AF7D00882579 /* Source */ = {
isa = XCSwiftPackageProductDependency;
productName = Source;
};
50628BDA28A8CD2300882579 /* Definition */ = {
isa = XCSwiftPackageProductDependency;
productName = Definition;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50307AAD28A75EA500598724 /* Project object */;
}
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/xcshareddata/xcschemes/CommandLineBridge.xcscheme
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Communicator/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Communicator/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Communicator",
products: [
.library(name: "Communicator", targets: ["Communicator"]),
],
targets: [
.target(name: "Communicator", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Communicator/Sources/Communicator/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Communicator/Sources/Communicator/Communicator.m
================================================
//
// Communicator.m
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import "Communicator.h"
NSData *argumentData;
__attribute__((constructor)) void communicator_constructor(void) {
NSString *message = [NSProcessInfo.processInfo.environment valueForKey:@"Communicator_Message"];
if (message.length <= 0) { return; }
NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NULL];
if (data == NULL || data.length <= 0) { return; }
argumentData = data;
}
@implementation Communicator
+ (NSData*)retrieveParentData {
return argumentData;
}
+ (void)sendRecipeDataAndExit:(NSString*)base64String {
NSLog(@"\nActionBee-Result-Recipe://%@", base64String);
exit(0);
}
@end
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Communicator/Sources/Communicator/include/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Definition/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Definition/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Definition",
products: [
.library(name: "Definition", targets: ["Definition"]),
],
targets: [
.target(name: "Definition", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/Definition/Sources/Definition/Definition.swift
================================================
import Foundation
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
public struct ArgumentData: Codable {
public let focusAppID: String?
public let focusAppName: String?
public let pasteboardContent: String
public init(focusAppID: String?, focusAppName: String?, pasteboardContent: String) {
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> ArgumentData? {
try? decoder.decode(ArgumentData.self, from: data)
}
}
public struct RecipeData: Codable {
public let postAction: PostAction
public let postContent: String
public let continueQueue: Bool
public enum PostAction: String, Codable {
case overwrite
case speak
case none
}
public init(postAction: PostAction, postContent: String, continueQueue: Bool) {
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> Self? {
try? decoder.decode(Self.self, from: data)
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/compile.sh
================================================
#!/bin/bash
# this compiler script is designed to issue binary to ./.build/cli
set -e
cd "$(dirname "$0")"/../
echo "[*] starting build at $(pwd)..."
if [ ! -f .action ]; then
exit 1
fi
echo "[*] cleaning build..."
rm -rf .build || true
mkdir .build
echo "[*] looking for target binary..."
BUILT_PRODUCTS_DIR=$(
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
-showBuildSettings \
CODE_SIGNING_ALLOWED="NO" \
2>/dev/null | grep -m 1 "BUILT_PRODUCTS_DIR" | grep -oEi "\/.*"
)
BINARY_LOCATION="$BUILT_PRODUCTS_DIR/CommandLineBridge"
# remove the binary
rm -f "$BINARY_LOCATION" || true
echo "[*] building binary to $BUILT_PRODUCTS_DIR..."
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
CODE_SIGNING_ALLOWED="NO" \
1>/dev/null 2>/dev/null
# check if the binary exists
if [ ! -f "$BINARY_LOCATION" ]; then
echo "[E] failed to emit binary at $BINARY_LOCATION"
exit 1
fi
echo "[*] copying binary..."
cp "$BINARY_LOCATION" .build/cli
echo "[*] signing binary..."
chmod +x .build/cli
codesign -s - --deep --force .build/cli 1>/dev/null 2>/dev/null
echo "[+] completed compile"
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/.supplement/launch.sh
================================================
#!/bin/bash
set -e
cd "$(dirname "$0")"/../
.build/cli
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/App.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/Source/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/Source/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Source",
products: [
.library(name: "Source", targets: ["Source"]),
],
dependencies: [
.package(name: "Definition", path: "./.supplement/Definition"),
],
targets: [
.target(name: "Source", dependencies: ["Definition"]),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Quick SFImage/Source/Sources/Source/Source.swift
================================================
// ActionBee
//
// Executable Source Template - v1.0
//
import Definition
import Foundation
import Cocoa
/*
⚠️
Only changes within the current directory will be committed to the compiler,
other modifications outside Source dir will be ignored when build.
You can add any package dependencies in Package.swift, process your need, and
build us a recipe.
*/
public enum ActionBee {
public static func solutionMain(event: ArgumentData, completion: @escaping (RecipeData?) -> Never) throws {
let text = event.pasteboardContent
if #available(macOS 11.0, *) {
if NSImage(systemSymbolName: text, accessibilityDescription: nil) != nil {
completion(.init(
postAction: .overwrite,
postContent: "Image(systemName: \"\(event.pasteboardContent)\")",
continueQueue: false
))
}
}
completion(.none)
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Binary/CommandLineBridge/CommandLineBridge/main.swift
================================================
//
// main.swift
// CommandLineBridge
//
// Created by Lakr Aream on 2022/8/13.
//
import Communicator
import Definition
import Foundation
import Source
guard let data = Communicator.retrieveParentData() else {
fatalError("unable to receive argument data")
}
guard let argument = ArgumentData.retrieve(withData: data) else {
fatalError("unable to receive argument object")
}
private let defaultRecipe: RecipeData = .init(
postAction: .none,
postContent: "",
continueQueue: true
)
let completion: ((RecipeData?) -> Never) = { recipe in
guard let recipe = recipe else {
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
guard let recipeBase64String = recipe.compileBase64() else {
fatalError("failed to compile recipe data")
}
Communicator.sendRecipeDataAndExit(recipeBase64String)
fatalError("malformed program flow")
}
do {
try ActionBee.solutionMain(event: argument, completion: completion)
} catch {
print(error.localizedDescription)
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
CFRunLoopRun()
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
50307AB928A75EA500598724 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50307AB828A75EA500598724 /* main.swift */; };
50307AC128A8AF0E00598724 /* Communicator in Frameworks */ = {isa = PBXBuildFile; productRef = 50307AC028A8AF0E00598724 /* Communicator */; };
50628BD928A8AF7D00882579 /* Source in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BD828A8AF7D00882579 /* Source */; };
50628BDB28A8CD2300882579 /* Definition in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BDA28A8CD2300882579 /* Definition */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
50307AB328A75EA500598724 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
50307AB528A75EA500598724 /* CommandLineBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLineBridge; sourceTree = BUILT_PRODUCTS_DIR; };
50307AB828A75EA500598724 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50307AB228A75EA500598724 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50307AC128A8AF0E00598724 /* Communicator in Frameworks */,
50628BD928A8AF7D00882579 /* Source in Frameworks */,
50628BDB28A8CD2300882579 /* Definition in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50307AAC28A75EA500598724 = {
isa = PBXGroup;
children = (
50307AB728A75EA500598724 /* CommandLineBridge */,
50307AB628A75EA500598724 /* Products */,
50307ABF28A8AF0B00598724 /* Frameworks */,
);
sourceTree = "";
};
50307AB628A75EA500598724 /* Products */ = {
isa = PBXGroup;
children = (
50307AB528A75EA500598724 /* CommandLineBridge */,
);
name = Products;
sourceTree = "";
};
50307AB728A75EA500598724 /* CommandLineBridge */ = {
isa = PBXGroup;
children = (
50307AB828A75EA500598724 /* main.swift */,
);
path = CommandLineBridge;
sourceTree = "";
};
50307ABF28A8AF0B00598724 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50307AB428A75EA500598724 /* CommandLineBridge */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */;
buildPhases = (
50307AB128A75EA500598724 /* Sources */,
50307AB228A75EA500598724 /* Frameworks */,
50307AB328A75EA500598724 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = CommandLineBridge;
packageProductDependencies = (
50307AC028A8AF0E00598724 /* Communicator */,
50628BD828A8AF7D00882579 /* Source */,
50628BDA28A8CD2300882579 /* Definition */,
);
productName = CommandLineBridge;
productReference = 50307AB528A75EA500598724 /* CommandLineBridge */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50307AAD28A75EA500598724 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
50307AB428A75EA500598724 = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50307AAC28A75EA500598724;
productRefGroup = 50307AB628A75EA500598724 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50307AB428A75EA500598724 /* CommandLineBridge */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
50307AB128A75EA500598724 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50307AB928A75EA500598724 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50307ABA28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
50307ABB28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
50307ABD28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
50307ABE28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABA28A75EA500598724 /* Debug */,
50307ABB28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABD28A75EA500598724 /* Debug */,
50307ABE28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
50307AC028A8AF0E00598724 /* Communicator */ = {
isa = XCSwiftPackageProductDependency;
productName = Communicator;
};
50628BD828A8AF7D00882579 /* Source */ = {
isa = XCSwiftPackageProductDependency;
productName = Source;
};
50628BDA28A8CD2300882579 /* Definition */ = {
isa = XCSwiftPackageProductDependency;
productName = Definition;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50307AAD28A75EA500598724 /* Project object */;
}
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/xcshareddata/xcschemes/CommandLineBridge.xcscheme
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Communicator/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Communicator/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Communicator",
products: [
.library(name: "Communicator", targets: ["Communicator"]),
],
targets: [
.target(name: "Communicator", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Communicator/Sources/Communicator/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Communicator/Sources/Communicator/Communicator.m
================================================
//
// Communicator.m
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import "Communicator.h"
NSData *argumentData;
__attribute__((constructor)) void communicator_constructor(void) {
NSString *message = [NSProcessInfo.processInfo.environment valueForKey:@"Communicator_Message"];
if (message.length <= 0) { return; }
NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NULL];
if (data == NULL || data.length <= 0) { return; }
argumentData = data;
}
@implementation Communicator
+ (NSData*)retrieveParentData {
return argumentData;
}
+ (void)sendRecipeDataAndExit:(NSString*)base64String {
NSLog(@"\nActionBee-Result-Recipe://%@", base64String);
exit(0);
}
@end
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Communicator/Sources/Communicator/include/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Definition/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Definition/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Definition",
products: [
.library(name: "Definition", targets: ["Definition"]),
],
targets: [
.target(name: "Definition", dependencies: []),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/Definition/Sources/Definition/Definition.swift
================================================
import Foundation
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
public struct ArgumentData: Codable {
public let focusAppID: String?
public let focusAppName: String?
public let pasteboardContent: String
public init(focusAppID: String?, focusAppName: String?, pasteboardContent: String) {
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> ArgumentData? {
try? decoder.decode(ArgumentData.self, from: data)
}
}
public struct RecipeData: Codable {
public let postAction: PostAction
public let postContent: String
public let continueQueue: Bool
public enum PostAction: String, Codable {
case overwrite
case speak
case none
}
public init(postAction: PostAction, postContent: String, continueQueue: Bool) {
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> Self? {
try? decoder.decode(Self.self, from: data)
}
}
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/compile.sh
================================================
#!/bin/bash
# this compiler script is designed to issue binary to ./.build/cli
set -e
cd "$(dirname "$0")"/../
echo "[*] starting build at $(pwd)..."
if [ ! -f .action ]; then
exit 1
fi
echo "[*] cleaning build..."
rm -rf .build || true
mkdir .build
echo "[*] looking for target binary..."
BUILT_PRODUCTS_DIR=$(
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
-showBuildSettings \
CODE_SIGNING_ALLOWED="NO" \
2>/dev/null | grep -m 1 "BUILT_PRODUCTS_DIR" | grep -oEi "\/.*"
)
BINARY_LOCATION="$BUILT_PRODUCTS_DIR/CommandLineBridge"
# remove the binary
rm -f "$BINARY_LOCATION" || true
echo "[*] building binary to $BUILT_PRODUCTS_DIR..."
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
CODE_SIGNING_ALLOWED="NO" \
1>/dev/null 2>/dev/null
# check if the binary exists
if [ ! -f "$BINARY_LOCATION" ]; then
echo "[E] failed to emit binary at $BINARY_LOCATION"
exit 1
fi
echo "[*] copying binary..."
cp "$BINARY_LOCATION" .build/cli
echo "[*] signing binary..."
chmod +x .build/cli
codesign -s - --deep --force .build/cli 1>/dev/null 2>/dev/null
echo "[+] completed compile"
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/.supplement/launch.sh
================================================
#!/bin/bash
set -e
cd "$(dirname "$0")"/../
.build/cli
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/App.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/Source/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/Source/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Source",
products: [
.library(name: "Source", targets: ["Source"]),
],
dependencies: [
.package(name: "Definition", path: "./.supplement/Definition"),
],
targets: [
.target(name: "Source", dependencies: ["Definition"]),
]
)
================================================
FILE: Resources/ModuleSample/Module Export - Speak Dictionary/Source/Sources/Source/Source.swift
================================================
// ActionBee
//
// Executable Source Template - v1.0
//
import Definition
import Foundation
/*
⚠️
Only changes within the current directory will be committed to the compiler,
other modifications outside Source dir will be ignored when build.
You can add any package dependencies in Package.swift, process your need, and
build us a recipe.
*/
public enum ActionBee {
public static func solutionMain(event: ArgumentData, completion: @escaping (RecipeData?) -> Never) throws {
completion(RecipeData(
postAction: .speak,
postContent: event.pasteboardContent,
continueQueue: false
))
}
}
================================================
FILE: Resources/ModuleTemplate/.templates
================================================
================================================
FILE: Resources/ModuleTemplate/Executable/ActionBeeModule.exec
================================================
================================================
FILE: Resources/ModuleTemplate/Executable/Put your binary here
================================================
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Binary/CommandLineBridge/CommandLineBridge/main.swift
================================================
//
// main.swift
// CommandLineBridge
//
// Created by Lakr Aream on 2022/8/13.
//
import Communicator
import Definition
import Foundation
import Source
guard let data = Communicator.retrieveParentData() else {
fatalError("unable to receive argument data")
}
guard let argument = ArgumentData.retrieve(withData: data) else {
fatalError("unable to receive argument object")
}
private let defaultRecipe: RecipeData = .init(
postAction: .none,
postContent: "",
continueQueue: true
)
let completion: ((RecipeData?) -> Never) = { recipe in
guard let recipe = recipe else {
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
guard let recipeBase64String = recipe.compileBase64() else {
fatalError("failed to compile recipe data")
}
Communicator.sendRecipeDataAndExit(recipeBase64String)
fatalError("malformed program flow")
}
do {
try ActionBee.solutionMain(event: argument, completion: completion)
} catch {
print(error.localizedDescription)
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
CFRunLoopRun()
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
50307AB928A75EA500598724 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50307AB828A75EA500598724 /* main.swift */; };
50307AC128A8AF0E00598724 /* Communicator in Frameworks */ = {isa = PBXBuildFile; productRef = 50307AC028A8AF0E00598724 /* Communicator */; };
50628BD928A8AF7D00882579 /* Source in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BD828A8AF7D00882579 /* Source */; };
50628BDB28A8CD2300882579 /* Definition in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BDA28A8CD2300882579 /* Definition */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
50307AB328A75EA500598724 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
50307AB528A75EA500598724 /* CommandLineBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLineBridge; sourceTree = BUILT_PRODUCTS_DIR; };
50307AB828A75EA500598724 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50307AB228A75EA500598724 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50307AC128A8AF0E00598724 /* Communicator in Frameworks */,
50628BD928A8AF7D00882579 /* Source in Frameworks */,
50628BDB28A8CD2300882579 /* Definition in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50307AAC28A75EA500598724 = {
isa = PBXGroup;
children = (
50307AB728A75EA500598724 /* CommandLineBridge */,
50307AB628A75EA500598724 /* Products */,
50307ABF28A8AF0B00598724 /* Frameworks */,
);
sourceTree = "";
};
50307AB628A75EA500598724 /* Products */ = {
isa = PBXGroup;
children = (
50307AB528A75EA500598724 /* CommandLineBridge */,
);
name = Products;
sourceTree = "";
};
50307AB728A75EA500598724 /* CommandLineBridge */ = {
isa = PBXGroup;
children = (
50307AB828A75EA500598724 /* main.swift */,
);
path = CommandLineBridge;
sourceTree = "";
};
50307ABF28A8AF0B00598724 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50307AB428A75EA500598724 /* CommandLineBridge */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */;
buildPhases = (
50307AB128A75EA500598724 /* Sources */,
50307AB228A75EA500598724 /* Frameworks */,
50307AB328A75EA500598724 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = CommandLineBridge;
packageProductDependencies = (
50307AC028A8AF0E00598724 /* Communicator */,
50628BD828A8AF7D00882579 /* Source */,
50628BDA28A8CD2300882579 /* Definition */,
);
productName = CommandLineBridge;
productReference = 50307AB528A75EA500598724 /* CommandLineBridge */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50307AAD28A75EA500598724 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
50307AB428A75EA500598724 = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50307AAC28A75EA500598724;
productRefGroup = 50307AB628A75EA500598724 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50307AB428A75EA500598724 /* CommandLineBridge */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
50307AB128A75EA500598724 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50307AB928A75EA500598724 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50307ABA28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
50307ABB28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
50307ABD28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
50307ABE28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABA28A75EA500598724 /* Debug */,
50307ABB28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABD28A75EA500598724 /* Debug */,
50307ABE28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
50307AC028A8AF0E00598724 /* Communicator */ = {
isa = XCSwiftPackageProductDependency;
productName = Communicator;
};
50628BD828A8AF7D00882579 /* Source */ = {
isa = XCSwiftPackageProductDependency;
productName = Source;
};
50628BDA28A8CD2300882579 /* Definition */ = {
isa = XCSwiftPackageProductDependency;
productName = Definition;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50307AAD28A75EA500598724 /* Project object */;
}
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/xcshareddata/xcschemes/CommandLineBridge.xcscheme
================================================
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Communicator/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Communicator/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Communicator",
products: [
.library(name: "Communicator", targets: ["Communicator"]),
],
targets: [
.target(name: "Communicator", dependencies: []),
]
)
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Communicator/Sources/Communicator/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Communicator/Sources/Communicator/Communicator.m
================================================
//
// Communicator.m
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import "Communicator.h"
NSData *argumentData;
__attribute__((constructor)) void communicator_constructor(void) {
NSString *message = [NSProcessInfo.processInfo.environment valueForKey:@"Communicator_Message"];
if (message.length <= 0) { return; }
NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NULL];
if (data == NULL || data.length <= 0) { return; }
argumentData = data;
}
@implementation Communicator
+ (NSData*)retrieveParentData {
return argumentData;
}
+ (void)sendRecipeDataAndExit:(NSString*)base64String {
NSLog(@"\nActionBee-Result-Recipe://%@", base64String);
exit(0);
}
@end
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Communicator/Sources/Communicator/include/Communicator.h
================================================
//
// Communicator.h
//
//
// Created by Lakr Aream on 2022/8/14.
//
#import
@interface Communicator : NSObject
+ (NSData* _Nullable )retrieveParentData;
+ (void)sendRecipeDataAndExit:(NSString* _Nonnull)base64String;
@end
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Definition/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Definition/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Definition",
products: [
.library(name: "Definition", targets: ["Definition"]),
],
targets: [
.target(name: "Definition", dependencies: []),
]
)
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/.supplement/Definition/Sources/Definition/Definition.swift
================================================
import Foundation
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
public struct ArgumentData: Codable {
public let focusAppID: String?
public let focusAppName: String?
public let pasteboardContent: String
public init(focusAppID: String?, focusAppName: String?, pasteboardContent: String) {
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> ArgumentData? {
try? decoder.decode(ArgumentData.self, from: data)
}
}
public struct RecipeData: Codable {
public let postAction: PostAction
public let postContent: String
public let continueQueue: Bool
public enum PostAction: String, Codable {
case overwrite
case speak
case none
}
public init(postAction: PostAction, postContent: String, continueQueue: Bool) {
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
}
public func compileBase64() -> String? {
(try? encoder.encode(self))?.base64EncodedString()
}
public static func retrieve(withData data: Data) -> Self? {
try? decoder.decode(Self.self, from: data)
}
}
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/App.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/Source/.gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/Source/Package.swift
================================================
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Source",
products: [
.library(name: "Source", targets: ["Source"]),
],
dependencies: [
.package(name: "Definition", path: "./.supplement/Definition"),
],
targets: [
.target(name: "Source", dependencies: ["Definition"]),
]
)
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/Source/Sources/Source/Source.swift
================================================
// ActionBee
//
// Executable Source Template - v1.0
//
import Definition
import Foundation
/*
⚠️
You are in charge to put result binary at designated location.
*/
public enum ActionBee {
public static func solutionMain(event: ArgumentData, completion: @escaping (RecipeData?) -> Never) throws {
// do your workflow here, but avoid changing the pasteboard
let appName = event.focusAppID
let appID = event.focusAppID
let content = event.pasteboardContent
print(
"""
====================
\(appName ?? "unknown app") - \(appID ?? "unknown app id")
\(content)
====================
"""
)
// after your work is done, return the recipe and tell parent to do the job
// return nil if failed to process
let result = RecipeData(
postAction: .speak,
postContent: "Hello World",
continueQueue: false
)
completion(result)
}
}
================================================
FILE: Resources/ModuleTemplate/ExecutableSwift/compile.command
================================================
#!/bin/bash
# this compiler script is designed to issue binary to ./.build/cli
set -e
cd "$(dirname "$0")"/
echo "[*] starting build at $(pwd)..."
echo "[*] cleaning build..."
rm -rf ActionBeeModule.exec || true
rm -rf .build || true
mkdir .build
echo "[*] looking for target binary..."
BUILT_PRODUCTS_DIR=$(
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
-showBuildSettings \
CODE_SIGNING_ALLOWED="NO" \
2>/dev/null | grep -m 1 "BUILT_PRODUCTS_DIR" | grep -oEi "\/.*"
)
BINARY_LOCATION="$BUILT_PRODUCTS_DIR/CommandLineBridge"
# remove the binary
rm -f "$BINARY_LOCATION" || true
echo "[*] building binary to $BUILT_PRODUCTS_DIR..."
xcodebuild \
clean build \
-configuration Release \
-workspace ./App.xcworkspace \
-scheme CommandLineBridge \
CODE_SIGNING_ALLOWED="NO" \
1>/dev/null 2>/dev/null
# check if the binary exists
if [ ! -f "$BINARY_LOCATION" ]; then
echo "[E] failed to emit binary at $BINARY_LOCATION"
exit 1
fi
echo "[*] copying binary..."
cp "$BINARY_LOCATION" .build/cli
echo "[*] signing binary..."
chmod +x .build/cli
codesign -s - --deep --force .build/cli 1>/dev/null 2>/dev/null
mv ./.build/cli ./ActionBeeModule.exec
echo "[+] completed compile"
================================================
FILE: Resources/ModuleTemplate/SourceNode/.eslintrc.js
================================================
module.exports = require('@innei/eslint-config-ts')
================================================
FILE: Resources/ModuleTemplate/SourceNode/.gitignore
================================================
node_modules
pnpm-lock.yaml
dist
yarn.lock
package-lock.json
.DS_Store
================================================
FILE: Resources/ModuleTemplate/SourceNode/.supplement/compile.sh
================================================
#!/bin/zsh
# this compiler script is designed to issue result to ./dist/index.js
export PATH=$PATH:/opt/homebrew/bin:/usr/local/bin
if ! [ -x "$(command -v npm)" ]; then
echo '[E] npm is not installed.' >&2
exit 1
fi
set -e
cd "$(dirname "$0")"/../
echo "[*] starting build at $(pwd)..."
if [ ! -f .action ]; then
echo "[E] malformed project architecture"
exit 1
fi
echo "[*] cleaning build..."
rm -rf dist || true
echo "[*] install dependencies..."
npm i
echo "[*] compile..."
npm run build
echo "[+] completed compile"
================================================
FILE: Resources/ModuleTemplate/SourceNode/package.json
================================================
{
"name": "action.bee.source.module.src",
"version": "0.0.0",
"description": "ActionBee Module Source Using Node",
"main": "./dist/index.js",
"scripts": {
"build": "ncc build src/index.ts -o dist"
},
"keywords": [],
"author": "Innei",
"license": "MIT",
"devDependencies": {
"@types/node": "18.7.8",
"@vercel/ncc": "0.34.0",
"typescript": "4.7.4"
}
}
================================================
FILE: Resources/ModuleTemplate/SourceNode/src/global.d.ts
================================================
declare global {
export interface ActionBeeMessageEvent {
focusAppID?: string
focusAppName?: string
pasteboardContent: string
}
export type ActionBeeAction = 'none' | 'overwrite' | 'speak'
}
export {}
================================================
FILE: Resources/ModuleTemplate/SourceNode/src/index.ts
================================================
// ActionBee - Node Module Template
// ⚠️ please put compiled your src into ./dist/index.js
function finalizeResult(
action: ActionBeeAction,
content: string,
continueQueue: boolean,
) {
const result = {
postAction: action, // none, overwrite, speak
postContent: content, // your content to post
continueQueue,
}
const base64 = Buffer.from(JSON.stringify(result)).toString('base64')
process.stderr.write(`\nActionBee-Result-Recipe://${base64}`)
process.exit(0)
}
function moduleMain() {
const messageFromEnv = process.env['Communicator_Message']
if (!messageFromEnv) {
process.stderr.write('ActionBee-Error: No message found')
return
}
const toString = Buffer.from(messageFromEnv, 'base64').toString()
const event: ActionBeeMessageEvent = JSON.parse(toString)
console.log(event.focusAppID) // optional
console.log(event.focusAppName) // optional
console.log(event.pasteboardContent) // string
finalizeResult('overwrite', 'Hello World', false)
}
moduleMain()
================================================
FILE: Resources/ModuleTemplate/SourceNode/tsconfig.json
================================================
{
"compilerOptions": {
"target": "ES2017",
"module": "CommonJS",
"declaration": false,
"allowJs": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "./src",
"resolveJsonModule": true,
"strict": true,
"esModuleInterop": true
}
}
================================================
FILE: Resources/ModuleTemplate/SourcePython/main.py
================================================
#!/usr/bin/env python3
import base64
import json
import os
from sys import stderr
# Write your code inside SolutionMain() function.
class PasteboardEvent:
def __init__(self, focusAppID, focusAppName, pasteboardContent):
self.focusAppID = focusAppID
self.focusAppName = focusAppName
self.pasteboardContent = pasteboardContent
class ActionBeeRecipe:
def __init__(self, postAction, postContent, continueQueue):
self.postAction = postAction
self.postContent = postContent
self.continueQueue = continueQueue
def finalizeAndSend(self):
message = json.dumps(self.__dict__)
b64msg = base64.b64encode(message.encode('utf-8'))
finalmsg = "\nActionBee-Result-Recipe://" + b64msg.decode('utf-8')
print(finalmsg, file=stderr)
exit(0)
def SolutionMain(event: PasteboardEvent) -> ActionBeeRecipe:
print(event.focusAppID)
print(event.focusAppName)
print(event.pasteboardContent)
return ActionBeeRecipe(
postAction="none", # none, overwrite, speak
postContent=event.pasteboardContent,
continueQueue=True
)
if __name__ == '__main__':
raw_event = base64.b64decode(
os.environ['Communicator_Message']).decode('utf-8')
json_object = json.loads(raw_event)
event = PasteboardEvent(
json_object['focusAppID'],
json_object['focusAppName'],
json_object['pasteboardContent']
)
recipe = SolutionMain(event)
recipe.finalizeAndSend()
================================================
FILE: Resources/ModuleTemplate/SourceSwift/.gitignore
================================================
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
!default.xcworkspace
*.dSYM
*.dSYM.zip
*.hmap
*.ipa
*.lcov
*.lock
*.log
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
*.pid
*.pid.lock
*.seed
*.swp
*.tgz
*.tsbuildinfo
*.xccheckout
*.xcscmblueprint
*.xcuserstate
*~.nib
.AppleDB
.AppleDesktop
.AppleDouble
.DS_Store
.DocumentRevisions-V100
.LSOverride
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
._*
.apdisk
.build
.bundle
.cache
.cache/
.com.apple.timemachine.donotpresent
.dynamodb/
.env
.env.test
.eslintcache
.fseventsd
.fusebox/
.grunt
.idea
.lock-wscript
.next
.node_repl_history
.npm
.nuxt
.nyc_output
.parcel-cache
.pnp.*
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
.serverless/
.swiftpm
.tern-port
.vscode-test
.vuepress/dist
.yarn-integrity
.yarn/build-state.yml
.yarn/cache
.yarn/unplugged
/*.gcno
Artifacts/
CI
CI-Pods.tar
Carthage/Build
Carthage/Build/
DerivedData
DerivedData/
Icon
Network Trash Folder
Pipeline/Dockers/Buildtime/
Podfile.lock
Pods/
Temporary Items
artifacts/
bower_components
build/
build/Release
coverage
default.profraw
dist
dockerbuild
dockermnt
fastlane/Preview.html
fastlane/report.xml
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
jspm_packages/
lerna-debug.log*
lib-cov
logs
node_modules/
npm-debug.log*
pids
profile
project.xcworkspace
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
temp/
temps/
web_modules/
xcuserdata
xcuserdata/
yarn-debug.log*
yarn-error.log*
================================================
FILE: Resources/ModuleTemplate/SourceSwift/.supplement/Binary/CommandLineBridge/CommandLineBridge/main.swift
================================================
//
// main.swift
// CommandLineBridge
//
// Created by Lakr Aream on 2022/8/13.
//
import Communicator
import Definition
import Foundation
import Source
guard let data = Communicator.retrieveParentData() else {
fatalError("unable to receive argument data")
}
guard let argument = ArgumentData.retrieve(withData: data) else {
fatalError("unable to receive argument object")
}
private let defaultRecipe: RecipeData = .init(
postAction: .none,
postContent: "",
continueQueue: true
)
let completion: ((RecipeData?) -> Never) = { recipe in
guard let recipe = recipe else {
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
guard let recipeBase64String = recipe.compileBase64() else {
fatalError("failed to compile recipe data")
}
Communicator.sendRecipeDataAndExit(recipeBase64String)
fatalError("malformed program flow")
}
do {
try ActionBee.solutionMain(event: argument, completion: completion)
} catch {
print(error.localizedDescription)
Communicator.sendRecipeDataAndExit(defaultRecipe.compileBase64()!)
fatalError("malformed program flow")
}
CFRunLoopRun()
================================================
FILE: Resources/ModuleTemplate/SourceSwift/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
50307AB928A75EA500598724 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50307AB828A75EA500598724 /* main.swift */; };
50307AC128A8AF0E00598724 /* Communicator in Frameworks */ = {isa = PBXBuildFile; productRef = 50307AC028A8AF0E00598724 /* Communicator */; };
50628BD928A8AF7D00882579 /* Source in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BD828A8AF7D00882579 /* Source */; };
50628BDB28A8CD2300882579 /* Definition in Frameworks */ = {isa = PBXBuildFile; productRef = 50628BDA28A8CD2300882579 /* Definition */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
50307AB328A75EA500598724 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
50307AB528A75EA500598724 /* CommandLineBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLineBridge; sourceTree = BUILT_PRODUCTS_DIR; };
50307AB828A75EA500598724 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50307AB228A75EA500598724 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50307AC128A8AF0E00598724 /* Communicator in Frameworks */,
50628BD928A8AF7D00882579 /* Source in Frameworks */,
50628BDB28A8CD2300882579 /* Definition in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50307AAC28A75EA500598724 = {
isa = PBXGroup;
children = (
50307AB728A75EA500598724 /* CommandLineBridge */,
50307AB628A75EA500598724 /* Products */,
50307ABF28A8AF0B00598724 /* Frameworks */,
);
sourceTree = "";
};
50307AB628A75EA500598724 /* Products */ = {
isa = PBXGroup;
children = (
50307AB528A75EA500598724 /* CommandLineBridge */,
);
name = Products;
sourceTree = "";
};
50307AB728A75EA500598724 /* CommandLineBridge */ = {
isa = PBXGroup;
children = (
50307AB828A75EA500598724 /* main.swift */,
);
path = CommandLineBridge;
sourceTree = "";
};
50307ABF28A8AF0B00598724 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50307AB428A75EA500598724 /* CommandLineBridge */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */;
buildPhases = (
50307AB128A75EA500598724 /* Sources */,
50307AB228A75EA500598724 /* Frameworks */,
50307AB328A75EA500598724 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = CommandLineBridge;
packageProductDependencies = (
50307AC028A8AF0E00598724 /* Communicator */,
50628BD828A8AF7D00882579 /* Source */,
50628BDA28A8CD2300882579 /* Definition */,
);
productName = CommandLineBridge;
productReference = 50307AB528A75EA500598724 /* CommandLineBridge */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50307AAD28A75EA500598724 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1400;
TargetAttributes = {
50307AB428A75EA500598724 = {
CreatedOnToolsVersion = 13.4.1;
};
};
};
buildConfigurationList = 50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50307AAC28A75EA500598724;
productRefGroup = 50307AB628A75EA500598724 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50307AB428A75EA500598724 /* CommandLineBridge */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
50307AB128A75EA500598724 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50307AB928A75EA500598724 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50307ABA28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
50307ABB28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
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;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
50307ABD28A75EA500598724 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
50307ABE28A75EA500598724 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50307AB028A75EA500598724 /* Build configuration list for PBXProject "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABA28A75EA500598724 /* Debug */,
50307ABB28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50307ABC28A75EA500598724 /* Build configuration list for PBXNativeTarget "CommandLineBridge" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50307ABD28A75EA500598724 /* Debug */,
50307ABE28A75EA500598724 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
50307AC028A8AF0E00598724 /* Communicator */ = {
isa = XCSwiftPackageProductDependency;
productName = Communicator;
};
50628BD828A8AF7D00882579 /* Source */ = {
isa = XCSwiftPackageProductDependency;
productName = Source;
};
50628BDA28A8CD2300882579 /* Definition */ = {
isa = XCSwiftPackageProductDependency;
productName = Definition;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 50307AAD28A75EA500598724 /* Project object */;
}
================================================
FILE: Resources/ModuleTemplate/SourceSwift/.supplement/Binary/CommandLineBridge/CommandLineBridge.xcodeproj/xcshareddata/xcschemes/CommandLineBridge.xcscheme
================================================