├── .github └── workflows │ └── test.yml ├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── Examples └── Example-iOS │ ├── Example-iOS.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── Example-iOS.xcscheme │ └── 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 ├── KeychainAccess.podspec ├── KeychainAccess.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── LICENSE ├── Lib ├── Configurations │ ├── Base.xcconfig │ ├── Debug.xcconfig │ ├── KeychainAccess.xcconfig │ ├── Release.xcconfig │ ├── TestHost.xcconfig │ └── Tests.xcconfig ├── KeychainAccess.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── KeychainAccess.xcscheme │ │ └── TestHost.xcscheme ├── KeychainAccess │ ├── Info.plist │ ├── Keychain.swift │ └── KeychainAccess.h ├── KeychainAccessTests │ ├── EnumTests.swift │ ├── ErrorTypeTests.swift │ ├── Info.plist │ ├── KeychainAccessTests.swift │ └── SharedCredentialTests.swift ├── TestHost-MacCatalyst │ ├── KeychainAccessTests-MacCatalyst │ │ ├── EnumTests.swift │ │ ├── ErrorTypeTests.swift │ │ ├── Info.plist │ │ └── KeychainAccessTests.swift │ ├── TestHost-MacCatalyst.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── TestHost-MacCatalyst.xcscheme │ └── 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 │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Info.plist │ └── TestHost.entitlements ├── Package.swift ├── Package@swift-5.3.swift ├── README.md └── Sources └── Keychain.swift /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | pull_request: 4 | branches: [master] 5 | push: 6 | branches: [master] 7 | workflow_dispatch: 8 | 9 | jobs: 10 | test: 11 | name: ${{ matrix.command }} on  ${{ matrix.platform }} (xcode ${{ matrix.xcode }}, ${{ matrix.macos }}) 12 | runs-on: ${{ matrix.macos }} 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | macos: ["macos-11", "macos-12", "macos-13"] 17 | xcode: ["11.7", "12.5.1", "13.2.1", "14.2", "14.3.1", "15.0.1"] 18 | platform: ["ios"] 19 | command: ["test"] 20 | exclude: 21 | - macos: "macos-11" 22 | xcode: "14.2" 23 | - macos: "macos-11" 24 | xcode: "14.3.1" 25 | - macos: "macos-11" 26 | xcode: "15.0.1" 27 | - macos: "macos-12" 28 | xcode: "11.7" 29 | - macos: "macos-12" 30 | xcode: "12.5.1" 31 | - macos: "macos-12" 32 | xcode: "13.2.1" 33 | - macos: "macos-12" 34 | xcode: "14.3.1" 35 | - macos: "macos-12" 36 | xcode: "15.0.1" 37 | - macos: "macos-13" 38 | xcode: "11.7" 39 | - macos: "macos-13" 40 | xcode: "12.5.1" 41 | - macos: "macos-13" 42 | xcode: "13.2.1" 43 | - macos: "macos-13" 44 | xcode: "14.2" 45 | steps: 46 | - uses: actions/checkout@v4 47 | - uses: maxim-lobanov/setup-xcode@v1.2.3 48 | with: 49 | xcode-version: ${{ matrix.xcode }} 50 | - name: Install the Apple certificate and provisioning profile 51 | env: 52 | BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} 53 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }} 54 | BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }} 55 | KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} 56 | run: | 57 | # create variables 58 | CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 59 | PP_PATH=$RUNNER_TEMP/build_pp.provisionprofile 60 | KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db 61 | 62 | # import certificate and provisioning profile from secrets 63 | echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH 64 | echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH 65 | 66 | # create temporary keychain 67 | security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 68 | security set-keychain-settings -lut 21600 $KEYCHAIN_PATH 69 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 70 | 71 | # import certificate to keychain 72 | security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH 73 | security list-keychain -d user -s $KEYCHAIN_PATH 74 | 75 | # apply provisioning profile 76 | mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles 77 | cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles 78 | - name: Test 79 | if: ${{ matrix.xcode=='11.7' && matrix.platform=='ios' }} 80 | run: | 81 | set -ex 82 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=13.7,name=iPhone 11 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults.xcresult 83 | - name: Test 84 | if: ${{ matrix.xcode=='12.5.1' && matrix.platform=='ios' }} 85 | run: | 86 | set -ex 87 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=14.5,name=iPhone 12 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults.xcresult 88 | - name: Test 89 | if: ${{ matrix.xcode=='13.2.1' && matrix.platform=='ios' }} 90 | run: | 91 | set -ex 92 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=15.2,name=iPhone 13 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults.xcresult 93 | - name: Test 94 | if: ${{ matrix.xcode=='14.2' && matrix.platform=='ios' }} 95 | run: | 96 | set -ex 97 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=16.2,name=iPhone 14 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults.xcresult 98 | - name: Test 99 | if: ${{ matrix.xcode=='14.3.1' && matrix.platform=='ios' }} 100 | run: | 101 | set -ex 102 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults1.xcresult 103 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=17.0.1,name=iPhone 14 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults2.xcresult 104 | xcrun xcresulttool merge TestResults1.xcresult TestResults2.xcresult --output-path TestResults.xcresult 105 | - name: Test 106 | if: ${{ matrix.xcode=='15.0.1' && matrix.platform=='ios' }} 107 | run: | 108 | set -ex 109 | xcodebuild test -workspace KeychainAccess.xcworkspace -scheme KeychainAccess -destination 'platform=iOS Simulator,OS=17.0.1,name=iPhone 15 Pro' -only-testing:KeychainAccessTests -resultBundlePath TestResults.xcresult 110 | - uses: kishikawakatsumi/xcresulttool@v1 111 | with: 112 | path: TestResults.xcresult 113 | title: "KeychainAccess test report" 114 | if: always() 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/2a4de265d37eca626309d8e115218d18985b5435/Swift.gitignore 2 | 3 | # Xcode 4 | # 5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 6 | 7 | ## User settings 8 | xcuserdata/ 9 | 10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 11 | *.xcscmblueprint 12 | *.xccheckout 13 | 14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 15 | build/ 16 | DerivedData/ 17 | *.moved-aside 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | 30 | ## App packaging 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | # *.xcodeproj 46 | # 47 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 48 | # hence it is not needed unless you have added a package configuration file to your project 49 | # .swiftpm 50 | 51 | .build/ 52 | 53 | # CocoaPods 54 | # 55 | # We recommend against adding the Pods directory to your .gitignore. However 56 | # you should judge for yourself, the pros and cons are mentioned at: 57 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 58 | # 59 | # Pods/ 60 | # 61 | # Add this line if you want to avoid checking in source code from the Xcode workspace 62 | # *.xcworkspace 63 | 64 | # Carthage 65 | # 66 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 67 | # Carthage/Checkouts 68 | 69 | Carthage/Build/ 70 | 71 | # Accio dependency management 72 | Dependencies/ 73 | .accio/ 74 | 75 | # fastlane 76 | # 77 | # It is recommended to not store the screenshots in the git repo. 78 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 79 | # For more information about the recommended setup visit: 80 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 81 | 82 | fastlane/report.xml 83 | fastlane/Preview.html 84 | fastlane/screenshots/**/*.png 85 | fastlane/test_output 86 | 87 | # Code Injection 88 | # 89 | # After new code Injection tools there's a generated folder /iOSInjectionProject 90 | # https://github.com/johnno1962/injectionforxcode 91 | 92 | iOSInjectionProject/ 93 | 94 | 95 | ### https://raw.github.com/github/gitignore/2a4de265d37eca626309d8e115218d18985b5435/Global/macOS.gitignore 96 | 97 | # General 98 | .DS_Store 99 | .AppleDouble 100 | .LSOverride 101 | 102 | # Icon must end with two \r 103 | Icon 104 | 105 | # Thumbnails 106 | ._* 107 | 108 | # Files that might appear in the root of a volume 109 | .DocumentRevisions-V100 110 | .fseventsd 111 | .Spotlight-V100 112 | .TemporaryItems 113 | .Trashes 114 | .VolumeIcon.icns 115 | .com.apple.timemachine.donotpresent 116 | 117 | # Directories potentially created on remote AFP share 118 | .AppleDB 119 | .AppleDesktop 120 | Network Trash Folder 121 | Temporary Items 122 | .apdisk 123 | 124 | 125 | ### https://raw.github.com/github/gitignore/2a4de265d37eca626309d8e115218d18985b5435/Ruby.gitignore 126 | 127 | *.gem 128 | *.rbc 129 | /.config 130 | /coverage/ 131 | /InstalledFiles 132 | /pkg/ 133 | /spec/reports/ 134 | /spec/examples.txt 135 | /test/tmp/ 136 | /test/version_tmp/ 137 | /tmp/ 138 | 139 | # Used by dotenv library to load environment variables. 140 | # .env 141 | 142 | # Ignore Byebug command history file. 143 | .byebug_history 144 | 145 | ## Specific to RubyMotion: 146 | .dat* 147 | .repl_history 148 | build/ 149 | *.bridgesupport 150 | build-iPhoneOS/ 151 | build-iPhoneSimulator/ 152 | 153 | ## Specific to RubyMotion (use of CocoaPods): 154 | # 155 | # We recommend against adding the Pods directory to your .gitignore. However 156 | # you should judge for yourself, the pros and cons are mentioned at: 157 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 158 | # 159 | # vendor/Pods/ 160 | 161 | ## Documentation cache and generated files: 162 | /.yardoc/ 163 | /_yardoc/ 164 | /doc/ 165 | /rdoc/ 166 | 167 | ## Environment normalization: 168 | /.bundle/ 169 | /vendor/bundle 170 | /lib/bundler/man/ 171 | 172 | # for a library or gem, you might want to ignore these files since the code is 173 | # intended to run in multiple environments; otherwise, check them in: 174 | # Gemfile.lock 175 | # .ruby-version 176 | # .ruby-gemset 177 | 178 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 179 | .rvmrc 180 | 181 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 182 | # .rubocop-https?--* 183 | 184 | 185 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 14DAEE961A51E1BE0070B77E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEE951A51E1BE0070B77E /* AppDelegate.swift */; }; 11 | 14DAEE9B1A51E1BE0070B77E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE991A51E1BE0070B77E /* Main.storyboard */; }; 12 | 14DAEE9D1A51E1BE0070B77E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE9C1A51E1BE0070B77E /* Images.xcassets */; }; 13 | 14DAEEA01A51E1BE0070B77E /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */; }; 14 | 14DAEEB71A51E2690070B77E /* AccountsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEEB51A51E2690070B77E /* AccountsViewController.swift */; }; 15 | 14DAEEB81A51E2690070B77E /* InputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEEB61A51E2690070B77E /* InputViewController.swift */; }; 16 | 14DAEEC91A51E2D00070B77E /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */; }; 17 | 14DAEECB1A51E2E10070B77E /* KeychainAccess.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 1470425D1D6FFA97005A4C6E /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */; 24 | proxyType = 2; 25 | remoteGlobalIDString = 14A630151D3293C700809B3F; 26 | remoteInfo = TestHost; 27 | }; 28 | 14DAEEC01A51E2A60070B77E /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */; 31 | proxyType = 2; 32 | remoteGlobalIDString = 140F195C1A49D79400B0016A; 33 | remoteInfo = "KeychainAccess-iOS"; 34 | }; 35 | 14DAEEC21A51E2A60070B77E /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */; 38 | proxyType = 2; 39 | remoteGlobalIDString = 140F19671A49D79500B0016A; 40 | remoteInfo = "KeychainAccess-iOSTests"; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXCopyFilesBuildPhase section */ 45 | 14DAEECA1A51E2D70070B77E /* CopyFiles */ = { 46 | isa = PBXCopyFilesBuildPhase; 47 | buildActionMask = 2147483647; 48 | dstPath = ""; 49 | dstSubfolderSpec = 10; 50 | files = ( 51 | 14DAEECB1A51E2E10070B77E /* KeychainAccess.framework in CopyFiles */, 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXCopyFilesBuildPhase section */ 56 | 57 | /* Begin PBXFileReference section */ 58 | 145652E11D898BB9006E8D0E /* Example-iOS.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Example-iOS.entitlements"; sourceTree = ""; }; 59 | 14DAEE901A51E1BE0070B77E /* Example-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 14DAEE941A51E1BE0070B77E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 14DAEE951A51E1BE0070B77E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 62 | 14DAEE9A1A51E1BE0070B77E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 63 | 14DAEE9C1A51E1BE0070B77E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 64 | 14DAEE9F1A51E1BE0070B77E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 65 | 14DAEEB51A51E2690070B77E /* AccountsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsViewController.swift; sourceTree = ""; }; 66 | 14DAEEB61A51E2690070B77E /* InputViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputViewController.swift; sourceTree = ""; }; 67 | 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KeychainAccess.xcodeproj; path = ../../Lib/KeychainAccess.xcodeproj; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | 14DAEE8D1A51E1BE0070B77E /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | 14DAEEC91A51E2D00070B77E /* KeychainAccess.framework in Frameworks */, 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | /* End PBXFrameworksBuildPhase section */ 80 | 81 | /* Begin PBXGroup section */ 82 | 14DAEE871A51E1BE0070B77E = { 83 | isa = PBXGroup; 84 | children = ( 85 | 14DAEE921A51E1BE0070B77E /* Example-iOS */, 86 | 14DAEE911A51E1BE0070B77E /* Products */, 87 | 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | 14DAEE911A51E1BE0070B77E /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 14DAEE901A51E1BE0070B77E /* Example-iOS.app */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | 14DAEE921A51E1BE0070B77E /* Example-iOS */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 14DAEE951A51E1BE0070B77E /* AppDelegate.swift */, 103 | 14DAEEB51A51E2690070B77E /* AccountsViewController.swift */, 104 | 14DAEEB61A51E2690070B77E /* InputViewController.swift */, 105 | 14DAEE991A51E1BE0070B77E /* Main.storyboard */, 106 | 14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */, 107 | 14DAEE9C1A51E1BE0070B77E /* Images.xcassets */, 108 | 14DAEE931A51E1BE0070B77E /* Supporting Files */, 109 | ); 110 | path = "Example-iOS"; 111 | sourceTree = ""; 112 | }; 113 | 14DAEE931A51E1BE0070B77E /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 14DAEE941A51E1BE0070B77E /* Info.plist */, 117 | 145652E11D898BB9006E8D0E /* Example-iOS.entitlements */, 118 | ); 119 | name = "Supporting Files"; 120 | sourceTree = ""; 121 | }; 122 | 14DAEEBA1A51E2A60070B77E /* Products */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */, 126 | 14DAEEC31A51E2A60070B77E /* KeychainAccessTests.xctest */, 127 | 1470425E1D6FFA97005A4C6E /* TestHost.app */, 128 | ); 129 | name = Products; 130 | sourceTree = ""; 131 | }; 132 | /* End PBXGroup section */ 133 | 134 | /* Begin PBXNativeTarget section */ 135 | 14DAEE8F1A51E1BE0070B77E /* Example-iOS */ = { 136 | isa = PBXNativeTarget; 137 | buildConfigurationList = 14DAEEAF1A51E1BE0070B77E /* Build configuration list for PBXNativeTarget "Example-iOS" */; 138 | buildPhases = ( 139 | 14DAEE8C1A51E1BE0070B77E /* Sources */, 140 | 14DAEE8D1A51E1BE0070B77E /* Frameworks */, 141 | 14DAEE8E1A51E1BE0070B77E /* Resources */, 142 | 14DAEECA1A51E2D70070B77E /* CopyFiles */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = "Example-iOS"; 149 | productName = "Example-iOS"; 150 | productReference = 14DAEE901A51E1BE0070B77E /* Example-iOS.app */; 151 | productType = "com.apple.product-type.application"; 152 | }; 153 | /* End PBXNativeTarget section */ 154 | 155 | /* Begin PBXProject section */ 156 | 14DAEE881A51E1BE0070B77E /* Project object */ = { 157 | isa = PBXProject; 158 | attributes = { 159 | LastSwiftUpdateCheck = 0700; 160 | LastUpgradeCheck = 1200; 161 | ORGANIZATIONNAME = "kishikawa katsumi"; 162 | TargetAttributes = { 163 | 14DAEE8F1A51E1BE0070B77E = { 164 | CreatedOnToolsVersion = 6.2; 165 | DevelopmentTeam = 27AEDK3C9F; 166 | LastSwiftMigration = 1100; 167 | }; 168 | }; 169 | }; 170 | buildConfigurationList = 14DAEE8B1A51E1BE0070B77E /* Build configuration list for PBXProject "Example-iOS" */; 171 | compatibilityVersion = "Xcode 3.2"; 172 | developmentRegion = en; 173 | hasScannedForEncodings = 0; 174 | knownRegions = ( 175 | en, 176 | Base, 177 | ); 178 | mainGroup = 14DAEE871A51E1BE0070B77E; 179 | productRefGroup = 14DAEE911A51E1BE0070B77E /* Products */; 180 | projectDirPath = ""; 181 | projectReferences = ( 182 | { 183 | ProductGroup = 14DAEEBA1A51E2A60070B77E /* Products */; 184 | ProjectRef = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */; 185 | }, 186 | ); 187 | projectRoot = ""; 188 | targets = ( 189 | 14DAEE8F1A51E1BE0070B77E /* Example-iOS */, 190 | ); 191 | }; 192 | /* End PBXProject section */ 193 | 194 | /* Begin PBXReferenceProxy section */ 195 | 1470425E1D6FFA97005A4C6E /* TestHost.app */ = { 196 | isa = PBXReferenceProxy; 197 | fileType = wrapper.application; 198 | path = TestHost.app; 199 | remoteRef = 1470425D1D6FFA97005A4C6E /* PBXContainerItemProxy */; 200 | sourceTree = BUILT_PRODUCTS_DIR; 201 | }; 202 | 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */ = { 203 | isa = PBXReferenceProxy; 204 | fileType = wrapper.framework; 205 | path = KeychainAccess.framework; 206 | remoteRef = 14DAEEC01A51E2A60070B77E /* PBXContainerItemProxy */; 207 | sourceTree = BUILT_PRODUCTS_DIR; 208 | }; 209 | 14DAEEC31A51E2A60070B77E /* KeychainAccessTests.xctest */ = { 210 | isa = PBXReferenceProxy; 211 | fileType = wrapper.cfbundle; 212 | path = KeychainAccessTests.xctest; 213 | remoteRef = 14DAEEC21A51E2A60070B77E /* PBXContainerItemProxy */; 214 | sourceTree = BUILT_PRODUCTS_DIR; 215 | }; 216 | /* End PBXReferenceProxy section */ 217 | 218 | /* Begin PBXResourcesBuildPhase section */ 219 | 14DAEE8E1A51E1BE0070B77E /* Resources */ = { 220 | isa = PBXResourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | 14DAEE9B1A51E1BE0070B77E /* Main.storyboard in Resources */, 224 | 14DAEEA01A51E1BE0070B77E /* LaunchScreen.xib in Resources */, 225 | 14DAEE9D1A51E1BE0070B77E /* Images.xcassets in Resources */, 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXResourcesBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 14DAEE8C1A51E1BE0070B77E /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 14DAEEB81A51E2690070B77E /* InputViewController.swift in Sources */, 237 | 14DAEEB71A51E2690070B77E /* AccountsViewController.swift in Sources */, 238 | 14DAEE961A51E1BE0070B77E /* AppDelegate.swift in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | /* End PBXSourcesBuildPhase section */ 243 | 244 | /* Begin PBXVariantGroup section */ 245 | 14DAEE991A51E1BE0070B77E /* Main.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 14DAEE9A1A51E1BE0070B77E /* Base */, 249 | ); 250 | name = Main.storyboard; 251 | sourceTree = ""; 252 | }; 253 | 14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | 14DAEE9F1A51E1BE0070B77E /* Base */, 257 | ); 258 | name = LaunchScreen.xib; 259 | sourceTree = ""; 260 | }; 261 | /* End PBXVariantGroup section */ 262 | 263 | /* Begin XCBuildConfiguration section */ 264 | 14DAEEAD1A51E1BE0070B77E /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 269 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 270 | CLANG_CXX_LIBRARY = "libc++"; 271 | CLANG_ENABLE_MODULES = YES; 272 | CLANG_ENABLE_OBJC_ARC = YES; 273 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 274 | CLANG_WARN_BOOL_CONVERSION = YES; 275 | CLANG_WARN_COMMA = YES; 276 | CLANG_WARN_CONSTANT_CONVERSION = YES; 277 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INFINITE_RECURSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 285 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 286 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 287 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 289 | CLANG_WARN_STRICT_PROTOTYPES = YES; 290 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | CODE_SIGN_ENTITLEMENTS = "Example-iOS/Example-iOS.entitlements"; 294 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 295 | COPY_PHASE_STRIP = NO; 296 | ENABLE_STRICT_OBJC_MSGSEND = YES; 297 | ENABLE_TESTABILITY = YES; 298 | GCC_C_LANGUAGE_STANDARD = gnu99; 299 | GCC_DYNAMIC_NO_PIC = NO; 300 | GCC_NO_COMMON_BLOCKS = YES; 301 | GCC_OPTIMIZATION_LEVEL = 0; 302 | GCC_PREPROCESSOR_DEFINITIONS = ( 303 | "DEBUG=1", 304 | "$(inherited)", 305 | ); 306 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 309 | GCC_WARN_UNDECLARED_SELECTOR = YES; 310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 311 | GCC_WARN_UNUSED_FUNCTION = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 314 | MTL_ENABLE_DEBUG_INFO = YES; 315 | ONLY_ACTIVE_ARCH = YES; 316 | SDKROOT = iphoneos; 317 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 318 | SWIFT_VERSION = 4.1; 319 | }; 320 | name = Debug; 321 | }; 322 | 14DAEEAE1A51E1BE0070B77E /* Release */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ALWAYS_SEARCH_USER_PATHS = NO; 326 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 328 | CLANG_CXX_LIBRARY = "libc++"; 329 | CLANG_ENABLE_MODULES = YES; 330 | CLANG_ENABLE_OBJC_ARC = YES; 331 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 332 | CLANG_WARN_BOOL_CONVERSION = YES; 333 | CLANG_WARN_COMMA = YES; 334 | CLANG_WARN_CONSTANT_CONVERSION = YES; 335 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 336 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 337 | CLANG_WARN_EMPTY_BODY = YES; 338 | CLANG_WARN_ENUM_CONVERSION = YES; 339 | CLANG_WARN_INFINITE_RECURSION = YES; 340 | CLANG_WARN_INT_CONVERSION = YES; 341 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 342 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 343 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 344 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 345 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 346 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 347 | CLANG_WARN_STRICT_PROTOTYPES = YES; 348 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 349 | CLANG_WARN_UNREACHABLE_CODE = YES; 350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 351 | CODE_SIGN_ENTITLEMENTS = "Example-iOS/Example-iOS.entitlements"; 352 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 353 | COPY_PHASE_STRIP = YES; 354 | ENABLE_NS_ASSERTIONS = NO; 355 | ENABLE_STRICT_OBJC_MSGSEND = YES; 356 | GCC_C_LANGUAGE_STANDARD = gnu99; 357 | GCC_NO_COMMON_BLOCKS = YES; 358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 360 | GCC_WARN_UNDECLARED_SELECTOR = YES; 361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 362 | GCC_WARN_UNUSED_FUNCTION = YES; 363 | GCC_WARN_UNUSED_VARIABLE = YES; 364 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 365 | MTL_ENABLE_DEBUG_INFO = NO; 366 | SDKROOT = iphoneos; 367 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 368 | SWIFT_VERSION = 4.1; 369 | VALIDATE_PRODUCT = YES; 370 | }; 371 | name = Release; 372 | }; 373 | 14DAEEB01A51E1BE0070B77E /* Debug */ = { 374 | isa = XCBuildConfiguration; 375 | buildSettings = { 376 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 377 | DEVELOPMENT_TEAM = 27AEDK3C9F; 378 | INFOPLIST_FILE = "Example-iOS/Info.plist"; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 380 | PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier)"; 381 | PRODUCT_NAME = "$(TARGET_NAME)"; 382 | SWIFT_VERSION = 5.0; 383 | }; 384 | name = Debug; 385 | }; 386 | 14DAEEB11A51E1BE0070B77E /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | DEVELOPMENT_TEAM = 27AEDK3C9F; 391 | INFOPLIST_FILE = "Example-iOS/Info.plist"; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 393 | PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier)"; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | SWIFT_VERSION = 5.0; 396 | }; 397 | name = Release; 398 | }; 399 | /* End XCBuildConfiguration section */ 400 | 401 | /* Begin XCConfigurationList section */ 402 | 14DAEE8B1A51E1BE0070B77E /* Build configuration list for PBXProject "Example-iOS" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | 14DAEEAD1A51E1BE0070B77E /* Debug */, 406 | 14DAEEAE1A51E1BE0070B77E /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | 14DAEEAF1A51E1BE0070B77E /* Build configuration list for PBXNativeTarget "Example-iOS" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 14DAEEB01A51E1BE0070B77E /* Debug */, 415 | 14DAEEB11A51E1BE0070B77E /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | /* End XCConfigurationList section */ 421 | }; 422 | rootObject = 14DAEE881A51E1BE0070B77E /* Project object */; 423 | } 424 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS.xcodeproj/xcshareddata/xcschemes/Example-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 51 | 52 | 53 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 76 | 78 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/AccountsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountsViewController.swift 3 | // Example 4 | // 5 | // Created by kishikawa katsumi on 2014/12/25. 6 | // Copyright (c) 2014 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | import KeychainAccess 28 | 29 | class AccountsViewController: UITableViewController { 30 | var itemsGroupedByService: [String: [[String: Any]]]? 31 | 32 | override func viewDidLoad() { 33 | super.viewDidLoad() 34 | } 35 | 36 | override func viewWillAppear(_ animated: Bool) { 37 | super.viewWillAppear(animated) 38 | 39 | reloadData() 40 | tableView.reloadData() 41 | } 42 | 43 | override func didReceiveMemoryWarning() { 44 | super.didReceiveMemoryWarning() 45 | } 46 | 47 | // MARK: 48 | 49 | override func numberOfSections(in tableView: UITableView) -> Int { 50 | if itemsGroupedByService != nil { 51 | let services = Array(itemsGroupedByService!.keys) 52 | return services.count 53 | } 54 | return 0 55 | } 56 | 57 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 58 | let services = Array(itemsGroupedByService!.keys) 59 | let service = services[section] 60 | 61 | let items = Keychain(service: service).allItems() 62 | return items.count 63 | } 64 | 65 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 66 | let services = Array(itemsGroupedByService!.keys) 67 | return services[section] 68 | } 69 | 70 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 71 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 72 | 73 | let services = Array(itemsGroupedByService!.keys) 74 | let service = services[indexPath.section] 75 | 76 | let items = Keychain(service: service).allItems() 77 | let item = items[indexPath.row] 78 | 79 | cell.textLabel?.text = item["key"] as? String 80 | cell.detailTextLabel?.text = item["value"] as? String 81 | 82 | return cell 83 | } 84 | 85 | #if swift(>=4.2) 86 | override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 87 | let services = Array(itemsGroupedByService!.keys) 88 | let service = services[indexPath.section] 89 | 90 | let keychain = Keychain(service: service) 91 | let items = keychain.allItems() 92 | 93 | let item = items[indexPath.row] 94 | let key = item["key"] as! String 95 | 96 | keychain[key] = nil 97 | 98 | if items.count == 1 { 99 | reloadData() 100 | tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic) 101 | } else { 102 | tableView.deleteRows(at: [indexPath], with: .automatic) 103 | } 104 | } 105 | #else 106 | override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 107 | let services = Array(itemsGroupedByService!.keys) 108 | let service = services[indexPath.section] 109 | 110 | let keychain = Keychain(service: service) 111 | let items = keychain.allItems() 112 | 113 | let item = items[indexPath.row] 114 | let key = item["key"] as! String 115 | 116 | keychain[key] = nil 117 | 118 | if items.count == 1 { 119 | reloadData() 120 | tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic) 121 | } else { 122 | tableView.deleteRows(at: [indexPath], with: .automatic) 123 | } 124 | } 125 | #endif 126 | 127 | // MARK: 128 | 129 | func reloadData() { 130 | let items = Keychain.allItems(.genericPassword) 131 | itemsGroupedByService = groupBy(items) { item -> String in 132 | if let service = item["service"] as? String { 133 | return service 134 | } 135 | return "" 136 | } 137 | } 138 | } 139 | 140 | private func groupBy(_ xs: C, key: (C.Iterator.Element) -> K) -> [K:[C.Iterator.Element]] { 141 | var gs: [K:[C.Iterator.Element]] = [:] 142 | for x in xs { 143 | let k = key(x) 144 | var ys = gs[k] ?? [] 145 | ys.append(x) 146 | gs.updateValue(ys, forKey: k) 147 | } 148 | return gs 149 | } 150 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by kishikawa katsumi on 2014/12/25. 6 | // Copyright (c) 2014 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | @UIApplicationMain 29 | class AppDelegate: UIResponder, UIApplicationDelegate { 30 | var window: UIWindow? 31 | 32 | #if swift(>=4.2) 33 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 34 | return true 35 | } 36 | #else 37 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { 38 | return true 39 | } 40 | #endif 41 | } 42 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/Example-iOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | keychain-access-groups 6 | 7 | $(AppIdentifierPrefix)com.kishikawakatsumi.Example-iOS 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Examples/Example-iOS/Example-iOS/InputViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InputViewController.swift 3 | // Example 4 | // 5 | // Created by kishikawa katsumi on 2014/12/26. 6 | // Copyright (c) 2014 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | import KeychainAccess 28 | 29 | class InputViewController: UITableViewController { 30 | 31 | @IBOutlet weak var saveButton: UIBarButtonItem! 32 | @IBOutlet weak var cancelButton: UIBarButtonItem! 33 | 34 | @IBOutlet weak var usernameField: UITextField! 35 | @IBOutlet weak var passwordField: UITextField! 36 | @IBOutlet weak var serviceField: UITextField! 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | 41 | tableView.rowHeight = 44.0 42 | tableView.estimatedRowHeight = 44.0 43 | } 44 | 45 | override func didReceiveMemoryWarning() { 46 | super.didReceiveMemoryWarning() 47 | } 48 | 49 | // MARK: 50 | 51 | @IBAction func cancelAction(sender: UIBarButtonItem) { 52 | dismiss(animated: true, completion: nil) 53 | } 54 | 55 | @IBAction func saveAction(sender: UIBarButtonItem) { 56 | let keychain: Keychain 57 | if let service = serviceField.text, !service.isEmpty { 58 | keychain = Keychain(service: service) 59 | } else { 60 | keychain = Keychain() 61 | } 62 | keychain[usernameField.text!] = passwordField.text 63 | 64 | dismiss(animated: true, completion: nil) 65 | } 66 | 67 | @IBAction func editingChanged(sender: UITextField) { 68 | switch (usernameField.text, passwordField.text) { 69 | case let (username?, password?): 70 | saveButton.isEnabled = !username.isEmpty && !password.isEmpty 71 | case (_?, nil): 72 | saveButton.isEnabled = false 73 | case (nil, _?): 74 | saveButton.isEnabled = false 75 | case (nil, nil): 76 | saveButton.isEnabled = false 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /KeychainAccess.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'KeychainAccess' 3 | s.version = '4.2.2' 4 | s.summary = 'KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and macOS.' 5 | s.description = <<-DESC 6 | KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and macOS. 7 | Makes using Keychain APIs exremely easy and much more palatable to use in Swift. 8 | 9 | Features 10 | - Simple interface 11 | - Support access group 12 | - Support accessibility 13 | - Support iCloud sharing 14 | - **Support TouchID and Keychain integration (iOS 8+)** 15 | - **Support Shared Web Credentials (iOS 8+)** 16 | - Works on both iOS & macOS 17 | - watchOS and tvOS are also supported 18 | DESC 19 | s.homepage = 'https://github.com/kishikawakatsumi/KeychainAccess' 20 | s.screenshots = 'https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/01.png' 21 | s.license = 'MIT' 22 | s.author = { 'kishikawa katsumi' => 'kishikawakatsumi@mac.com' } 23 | s.source = { :git => 'https://github.com/kishikawakatsumi/KeychainAccess.git', :tag => "v#{s.version}" } 24 | s.social_media_url = 'https://twitter.com/k_katsumi' 25 | 26 | s.requires_arc = true 27 | s.source_files = 'Lib/KeychainAccess/*.swift' 28 | 29 | s.swift_version = '5.1' 30 | 31 | s.ios.deployment_target = '9.0' 32 | s.osx.deployment_target = '10.9' 33 | s.watchos.deployment_target = '3.0' 34 | s.tvos.deployment_target = '9.0' 35 | end 36 | -------------------------------------------------------------------------------- /KeychainAccess.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /KeychainAccess.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 kishikawa katsumi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Lib/Configurations/Base.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_SEARCH_USER_PATHS = NO; 2 | CLANG_ANALYZER_NONNULL = YES 3 | CLANG_CXX_LANGUAGE_STANDARD = gnu++0x; 4 | CLANG_CXX_LIBRARY = libc++; 5 | CLANG_ENABLE_MODULES = YES; 6 | CLANG_ENABLE_OBJC_ARC = YES; 7 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 8 | CLANG_WARN_BOOL_CONVERSION = YES; 9 | CLANG_WARN_COMMA = YES; 10 | CLANG_WARN_CONSTANT_CONVERSION = YES; 11 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 12 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 13 | CLANG_WARN_EMPTY_BODY = YES; 14 | CLANG_WARN_ENUM_CONVERSION = YES; 15 | CLANG_WARN_INFINITE_RECURSION = YES; 16 | CLANG_WARN_INT_CONVERSION = YES; 17 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 18 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 19 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 20 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 21 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 22 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 23 | CLANG_WARN_STRICT_PROTOTYPES = YES; 24 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 25 | CLANG_WARN_UNREACHABLE_CODE = YES; 26 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 27 | CURRENT_PROJECT_VERSION = 1; 28 | ENABLE_STRICT_OBJC_MSGSEND = YES; 29 | GCC_C_LANGUAGE_STANDARD = gnu99; 30 | GCC_NO_COMMON_BLOCKS = YES; 31 | GCC_DYNAMIC_NO_PIC = NO; 32 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 33 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 34 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 35 | GCC_WARN_UNDECLARED_SELECTOR = YES; 36 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 37 | GCC_WARN_UNUSED_FUNCTION = YES; 38 | GCC_WARN_UNUSED_VARIABLE = YES; 39 | VERSIONING_SYSTEM = "apple-generic"; 40 | VERSION_INFO_PREFIX = ""; 41 | 42 | CODE_SIGN_IDENTITY = ; 43 | DEVELOPMENT_TEAM = ; 44 | 45 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 46 | WATCHOS_DEPLOYMENT_TARGET = 3.0; 47 | TVOS_DEPLOYMENT_TARGET = 9.0; 48 | MACOSX_DEPLOYMENT_TARGET = 10.9; 49 | 50 | SWIFT_VERSION = 5.0; 51 | -------------------------------------------------------------------------------- /Lib/Configurations/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Base.xcconfig" 2 | 3 | BITCODE_GENERATION_MODE = marker; 4 | MTL_ENABLE_DEBUG_INFO = YES; 5 | COPY_PHASE_STRIP = NO; 6 | ENABLE_TESTABILITY = YES; 7 | GCC_OPTIMIZATION_LEVEL = 0; 8 | ONLY_ACTIVE_ARCH = YES; 9 | SWIFT_OPTIMIZATION_LEVEL = -Onone; 10 | 11 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1; 12 | -------------------------------------------------------------------------------- /Lib/Configurations/KeychainAccess.xcconfig: -------------------------------------------------------------------------------- 1 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator; 2 | TARGETED_DEVICE_FAMILY = 1,2,3,4; 3 | SUPPORTS_MACCATALYST = YES; 4 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; 5 | 6 | COMBINE_HIDPI_IMAGES = YES; 7 | PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.$(PLATFORM_NAME).$(PRODUCT_NAME:rfc1034identifier); 8 | PRODUCT_NAME = $(PROJECT_NAME); 9 | APPLICATION_EXTENSION_API_ONLY = YES; 10 | INFOPLIST_FILE = KeychainAccess/Info.plist; 11 | SKIP_INSTALL = YES; 12 | 13 | BUILD_LIBRARY_FOR_DISTRIBUTION = YES; 14 | DEFINES_MODULE = YES; 15 | DYLIB_COMPATIBILITY_VERSION = 1; 16 | DYLIB_CURRENT_VERSION = 1; 17 | DYLIB_INSTALL_NAME_BASE = @rpath; 18 | 19 | ENABLE_BITCODE[sdk=iphone*] = YES; 20 | ENABLE_BITCODE[sdk=watch*] = YES; 21 | ENABLE_BITCODE[sdk=appletv*] = YES; 22 | 23 | LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 24 | LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 25 | LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 26 | LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks; 27 | -------------------------------------------------------------------------------- /Lib/Configurations/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Base.xcconfig" 2 | 3 | BITCODE_GENERATION_MODE = bitcode; 4 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 5 | ENABLE_NS_ASSERTIONS = NO; 6 | MTL_ENABLE_DEBUG_INFO = NO; 7 | VALIDATE_PRODUCT = YES; 8 | SWIFT_COMPILATION_MODE = wholemodule; 9 | SWIFT_OPTIMIZATION_LEVEL = -Owholemodule; 10 | -------------------------------------------------------------------------------- /Lib/Configurations/TestHost.xcconfig: -------------------------------------------------------------------------------- 1 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator; 2 | TARGETED_DEVICE_FAMILY = 1,2,3; 3 | SUPPORTS_MACCATALYST = YES; 4 | 5 | COMBINE_HIDPI_IMAGES = YES; 6 | COPY_PHASE_STRIP = NO; 7 | INFOPLIST_FILE = TestHost/Info.plist; 8 | PRODUCT_NAME = $(TARGET_NAME); 9 | CLANG_MODULES_AUTOLINK = NO; 10 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 11 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 12 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.KeychainAccess.TestHost; 15 | 16 | CODE_SIGN_ENTITLEMENTS = TestHost/TestHost.entitlements; 17 | 18 | CODE_SIGN_IDENTITY[sdk=iphone*] = iPhone Developer; 19 | CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application; 20 | PROVISIONING_PROFILE_SPECIFIER[sdk=iphone*] = iOS Development; 21 | PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = KeychainAccess Tests; 22 | 23 | DEVELOPMENT_TEAM = 27AEDK3C9F; 24 | 25 | PRINCIPAL_CLASS[sdk=iphone*] = UIApplication; 26 | PRINCIPAL_CLASS[sdk=appletv*] = UIApplication; 27 | PRINCIPAL_CLASS[sdk=macosx*] = NSApplication; 28 | 29 | LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 30 | LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 31 | LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 32 | LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks; 33 | -------------------------------------------------------------------------------- /Lib/Configurations/Tests.xcconfig: -------------------------------------------------------------------------------- 1 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator; 2 | TARGETED_DEVICE_FAMILY = 1,2; 3 | SUPPORTS_MACCATALYST = YES; 4 | 5 | COMBINE_HIDPI_IMAGES = YES; 6 | PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier); 7 | PRODUCT_NAME = $(TARGET_NAME); 8 | APPLICATION_EXTENSION_API_ONLY = NO; 9 | INFOPLIST_FILE = KeychainAccessTests/Info.plist; 10 | 11 | LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 12 | LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 13 | LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks; 14 | LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks; 15 | 16 | TEST_HOST[sdk=iphone*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost; 17 | TEST_HOST[sdk=appletv*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost; 18 | TEST_HOST[sdk=macosx*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/Contents/MacOS/TestHost; 19 | 20 | EXCLUDED_SOURCE_FILE_NAMES[sdk=watch*] = *; 21 | EXCLUDED_SOURCE_FILE_NAMES[sdk=appletv*] = SharedCredentialTests.swift; 22 | EXCLUDED_SOURCE_FILE_NAMES[sdk=macosx*] = SharedCredentialTests.swift; 23 | 24 | DEVELOPMENT_TEAM = 27AEDK3C9F; 25 | -------------------------------------------------------------------------------- /Lib/KeychainAccess.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 140F19621A49D79400B0016A /* KeychainAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 140F19611A49D79400B0016A /* KeychainAccess.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 140F196F1A49D79500B0016A /* KeychainAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140F196E1A49D79500B0016A /* KeychainAccessTests.swift */; }; 12 | 140F197B1A49D89200B0016A /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140F197A1A49D89200B0016A /* Keychain.swift */; }; 13 | 142EDA851BCB505F00A32149 /* ErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */; }; 14 | 142EDB041BCBB0DD00A32149 /* SharedCredentialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */; }; 15 | 148F9D4A1BCB4118006EDF48 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148F9D491BCB4118006EDF48 /* EnumTests.swift */; }; 16 | 14A630181D3293C700809B3F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A630171D3293C700809B3F /* AppDelegate.swift */; }; 17 | 14A6301F1D3293C700809B3F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14A6301E1D3293C700809B3F /* Assets.xcassets */; }; 18 | 14C3A6781D32BF9C00349459 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; }; 19 | 14C3A6791D32BF9C00349459 /* KeychainAccess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 140F19691A49D79500B0016A /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 140F19531A49D79400B0016A /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 140F195B1A49D79400B0016A; 28 | remoteInfo = KeychainAccess; 29 | }; 30 | 14C3A67A1D32BF9C00349459 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 140F19531A49D79400B0016A /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 140F195B1A49D79400B0016A; 35 | remoteInfo = KeychainAccess; 36 | }; 37 | 14F0C1991D32A160007DCDDB /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 140F19531A49D79400B0016A /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = 14A630141D3293C700809B3F; 42 | remoteInfo = TestHost; 43 | }; 44 | /* End PBXContainerItemProxy section */ 45 | 46 | /* Begin PBXCopyFilesBuildPhase section */ 47 | 14C3A67C1D32BF9D00349459 /* Embed Frameworks */ = { 48 | isa = PBXCopyFilesBuildPhase; 49 | buildActionMask = 2147483647; 50 | dstPath = ""; 51 | dstSubfolderSpec = 10; 52 | files = ( 53 | 14C3A6791D32BF9C00349459 /* KeychainAccess.framework in Embed Frameworks */, 54 | ); 55 | name = "Embed Frameworks"; 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXCopyFilesBuildPhase section */ 59 | 60 | /* Begin PBXFileReference section */ 61 | 140F195C1A49D79400B0016A /* KeychainAccess.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KeychainAccess.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 140F19601A49D79400B0016A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 140F19611A49D79400B0016A /* KeychainAccess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainAccess.h; sourceTree = ""; }; 64 | 140F19671A49D79500B0016A /* KeychainAccessTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainAccessTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 140F196D1A49D79500B0016A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | 140F196E1A49D79500B0016A /* KeychainAccessTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainAccessTests.swift; sourceTree = ""; }; 67 | 140F197A1A49D89200B0016A /* Keychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; 68 | 142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorTypeTests.swift; sourceTree = ""; }; 69 | 142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedCredentialTests.swift; sourceTree = ""; }; 70 | 148E44E51BF9EDCB004FFEC1 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = Configurations/Base.xcconfig; sourceTree = ""; }; 71 | 148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = ""; }; 72 | 148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = ""; }; 73 | 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Tests.xcconfig; path = Configurations/Tests.xcconfig; sourceTree = ""; }; 74 | 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = KeychainAccess.xcconfig; path = Configurations/KeychainAccess.xcconfig; sourceTree = ""; }; 75 | 148F9D491BCB4118006EDF48 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = ""; }; 76 | 14A630151D3293C700809B3F /* TestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHost.app; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | 14A630171D3293C700809B3F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 78 | 14A6301E1D3293C700809B3F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 79 | 14A630231D3293C700809B3F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | 14F0C1961D3295C4007DCDDB /* TestHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TestHost.entitlements; sourceTree = ""; }; 81 | 14F0C1981D329832007DCDDB /* TestHost.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = TestHost.xcconfig; path = Configurations/TestHost.xcconfig; sourceTree = ""; }; 82 | /* End PBXFileReference section */ 83 | 84 | /* Begin PBXFrameworksBuildPhase section */ 85 | 140F19581A49D79400B0016A /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | 140F19641A49D79500B0016A /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 14A630121D3293C700809B3F /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | 14C3A6781D32BF9C00349459 /* KeychainAccess.framework in Frameworks */, 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | /* End PBXFrameworksBuildPhase section */ 108 | 109 | /* Begin PBXGroup section */ 110 | 140F19521A49D79400B0016A = { 111 | isa = PBXGroup; 112 | children = ( 113 | 140F195E1A49D79400B0016A /* KeychainAccess */, 114 | 140F196B1A49D79500B0016A /* KeychainAccessTests */, 115 | 148E44E41BF9ED6D004FFEC1 /* Cofigurations */, 116 | 14A630161D3293C700809B3F /* TestHost */, 117 | 140F195D1A49D79400B0016A /* Products */, 118 | ); 119 | sourceTree = ""; 120 | }; 121 | 140F195D1A49D79400B0016A /* Products */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 140F195C1A49D79400B0016A /* KeychainAccess.framework */, 125 | 140F19671A49D79500B0016A /* KeychainAccessTests.xctest */, 126 | 14A630151D3293C700809B3F /* TestHost.app */, 127 | ); 128 | name = Products; 129 | sourceTree = ""; 130 | }; 131 | 140F195E1A49D79400B0016A /* KeychainAccess */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 140F19611A49D79400B0016A /* KeychainAccess.h */, 135 | 140F197A1A49D89200B0016A /* Keychain.swift */, 136 | 140F195F1A49D79400B0016A /* Supporting Files */, 137 | ); 138 | path = KeychainAccess; 139 | sourceTree = ""; 140 | }; 141 | 140F195F1A49D79400B0016A /* Supporting Files */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 140F19601A49D79400B0016A /* Info.plist */, 145 | ); 146 | name = "Supporting Files"; 147 | sourceTree = ""; 148 | }; 149 | 140F196B1A49D79500B0016A /* KeychainAccessTests */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 140F196E1A49D79500B0016A /* KeychainAccessTests.swift */, 153 | 148F9D491BCB4118006EDF48 /* EnumTests.swift */, 154 | 142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */, 155 | 142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */, 156 | 140F196C1A49D79500B0016A /* Supporting Files */, 157 | ); 158 | path = KeychainAccessTests; 159 | sourceTree = ""; 160 | }; 161 | 140F196C1A49D79500B0016A /* Supporting Files */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 140F196D1A49D79500B0016A /* Info.plist */, 165 | ); 166 | name = "Supporting Files"; 167 | sourceTree = ""; 168 | }; 169 | 148E44E41BF9ED6D004FFEC1 /* Cofigurations */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 148E44E51BF9EDCB004FFEC1 /* Base.xcconfig */, 173 | 148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */, 174 | 148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */, 175 | 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */, 176 | 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */, 177 | 14F0C1981D329832007DCDDB /* TestHost.xcconfig */, 178 | ); 179 | name = Cofigurations; 180 | sourceTree = ""; 181 | }; 182 | 14A630161D3293C700809B3F /* TestHost */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 14A630171D3293C700809B3F /* AppDelegate.swift */, 186 | 14A6301E1D3293C700809B3F /* Assets.xcassets */, 187 | 14A630231D3293C700809B3F /* Info.plist */, 188 | 14F0C1961D3295C4007DCDDB /* TestHost.entitlements */, 189 | ); 190 | path = TestHost; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXGroup section */ 194 | 195 | /* Begin PBXHeadersBuildPhase section */ 196 | 140F19591A49D79400B0016A /* Headers */ = { 197 | isa = PBXHeadersBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | 140F19621A49D79400B0016A /* KeychainAccess.h in Headers */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | /* End PBXHeadersBuildPhase section */ 205 | 206 | /* Begin PBXNativeTarget section */ 207 | 140F195B1A49D79400B0016A /* KeychainAccess */ = { 208 | isa = PBXNativeTarget; 209 | buildConfigurationList = 140F19721A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccess" */; 210 | buildPhases = ( 211 | 140F19571A49D79400B0016A /* Sources */, 212 | 140F19581A49D79400B0016A /* Frameworks */, 213 | 140F19591A49D79400B0016A /* Headers */, 214 | 140F195A1A49D79400B0016A /* Resources */, 215 | ); 216 | buildRules = ( 217 | ); 218 | dependencies = ( 219 | ); 220 | name = KeychainAccess; 221 | productName = KeychainAccess; 222 | productReference = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; 223 | productType = "com.apple.product-type.framework"; 224 | }; 225 | 140F19661A49D79500B0016A /* KeychainAccessTests */ = { 226 | isa = PBXNativeTarget; 227 | buildConfigurationList = 140F19751A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccessTests" */; 228 | buildPhases = ( 229 | 140F19631A49D79500B0016A /* Sources */, 230 | 140F19641A49D79500B0016A /* Frameworks */, 231 | 140F19651A49D79500B0016A /* Resources */, 232 | ); 233 | buildRules = ( 234 | ); 235 | dependencies = ( 236 | 140F196A1A49D79500B0016A /* PBXTargetDependency */, 237 | 14F0C19A1D32A160007DCDDB /* PBXTargetDependency */, 238 | ); 239 | name = KeychainAccessTests; 240 | productName = KeychainAccessTests; 241 | productReference = 140F19671A49D79500B0016A /* KeychainAccessTests.xctest */; 242 | productType = "com.apple.product-type.bundle.unit-test"; 243 | }; 244 | 14A630141D3293C700809B3F /* TestHost */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = 14A630241D3293C700809B3F /* Build configuration list for PBXNativeTarget "TestHost" */; 247 | buildPhases = ( 248 | 14A630111D3293C700809B3F /* Sources */, 249 | 14A630121D3293C700809B3F /* Frameworks */, 250 | 14A630131D3293C700809B3F /* Resources */, 251 | 14C3A67C1D32BF9D00349459 /* Embed Frameworks */, 252 | ); 253 | buildRules = ( 254 | ); 255 | dependencies = ( 256 | 14C3A67B1D32BF9C00349459 /* PBXTargetDependency */, 257 | ); 258 | name = TestHost; 259 | productName = TestHost; 260 | productReference = 14A630151D3293C700809B3F /* TestHost.app */; 261 | productType = "com.apple.product-type.application"; 262 | }; 263 | /* End PBXNativeTarget section */ 264 | 265 | /* Begin PBXProject section */ 266 | 140F19531A49D79400B0016A /* Project object */ = { 267 | isa = PBXProject; 268 | attributes = { 269 | LastSwiftUpdateCheck = 0730; 270 | LastUpgradeCheck = 1200; 271 | ORGANIZATIONNAME = "kishikawa katsumi"; 272 | TargetAttributes = { 273 | 140F195B1A49D79400B0016A = { 274 | CreatedOnToolsVersion = 6.1.1; 275 | DevelopmentTeam = 27AEDK3C9F; 276 | LastSwiftMigration = 1020; 277 | ProvisioningStyle = Automatic; 278 | }; 279 | 140F19661A49D79500B0016A = { 280 | CreatedOnToolsVersion = 6.1.1; 281 | DevelopmentTeam = 27AEDK3C9F; 282 | LastSwiftMigration = 1020; 283 | ProvisioningStyle = Automatic; 284 | TestTargetID = 14A62FFC1D32922C00809B3F; 285 | }; 286 | 14A630141D3293C700809B3F = { 287 | CreatedOnToolsVersion = 7.3.1; 288 | DevelopmentTeam = 27AEDK3C9F; 289 | LastSwiftMigration = 1020; 290 | SystemCapabilities = { 291 | com.apple.Keychain = { 292 | enabled = 1; 293 | }; 294 | }; 295 | }; 296 | }; 297 | }; 298 | buildConfigurationList = 140F19561A49D79400B0016A /* Build configuration list for PBXProject "KeychainAccess" */; 299 | compatibilityVersion = "Xcode 3.2"; 300 | developmentRegion = en; 301 | hasScannedForEncodings = 0; 302 | knownRegions = ( 303 | en, 304 | Base, 305 | ); 306 | mainGroup = 140F19521A49D79400B0016A; 307 | productRefGroup = 140F195D1A49D79400B0016A /* Products */; 308 | projectDirPath = ""; 309 | projectRoot = ""; 310 | targets = ( 311 | 140F195B1A49D79400B0016A /* KeychainAccess */, 312 | 140F19661A49D79500B0016A /* KeychainAccessTests */, 313 | 14A630141D3293C700809B3F /* TestHost */, 314 | ); 315 | }; 316 | /* End PBXProject section */ 317 | 318 | /* Begin PBXResourcesBuildPhase section */ 319 | 140F195A1A49D79400B0016A /* Resources */ = { 320 | isa = PBXResourcesBuildPhase; 321 | buildActionMask = 2147483647; 322 | files = ( 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | 140F19651A49D79500B0016A /* Resources */ = { 327 | isa = PBXResourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | 14A630131D3293C700809B3F /* Resources */ = { 334 | isa = PBXResourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | 14A6301F1D3293C700809B3F /* Assets.xcassets in Resources */, 338 | ); 339 | runOnlyForDeploymentPostprocessing = 0; 340 | }; 341 | /* End PBXResourcesBuildPhase section */ 342 | 343 | /* Begin PBXSourcesBuildPhase section */ 344 | 140F19571A49D79400B0016A /* Sources */ = { 345 | isa = PBXSourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 140F197B1A49D89200B0016A /* Keychain.swift in Sources */, 349 | ); 350 | runOnlyForDeploymentPostprocessing = 0; 351 | }; 352 | 140F19631A49D79500B0016A /* Sources */ = { 353 | isa = PBXSourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 140F196F1A49D79500B0016A /* KeychainAccessTests.swift in Sources */, 357 | 148F9D4A1BCB4118006EDF48 /* EnumTests.swift in Sources */, 358 | 142EDA851BCB505F00A32149 /* ErrorTypeTests.swift in Sources */, 359 | 142EDB041BCBB0DD00A32149 /* SharedCredentialTests.swift in Sources */, 360 | ); 361 | runOnlyForDeploymentPostprocessing = 0; 362 | }; 363 | 14A630111D3293C700809B3F /* Sources */ = { 364 | isa = PBXSourcesBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | 14A630181D3293C700809B3F /* AppDelegate.swift in Sources */, 368 | ); 369 | runOnlyForDeploymentPostprocessing = 0; 370 | }; 371 | /* End PBXSourcesBuildPhase section */ 372 | 373 | /* Begin PBXTargetDependency section */ 374 | 140F196A1A49D79500B0016A /* PBXTargetDependency */ = { 375 | isa = PBXTargetDependency; 376 | target = 140F195B1A49D79400B0016A /* KeychainAccess */; 377 | targetProxy = 140F19691A49D79500B0016A /* PBXContainerItemProxy */; 378 | }; 379 | 14C3A67B1D32BF9C00349459 /* PBXTargetDependency */ = { 380 | isa = PBXTargetDependency; 381 | target = 140F195B1A49D79400B0016A /* KeychainAccess */; 382 | targetProxy = 14C3A67A1D32BF9C00349459 /* PBXContainerItemProxy */; 383 | }; 384 | 14F0C19A1D32A160007DCDDB /* PBXTargetDependency */ = { 385 | isa = PBXTargetDependency; 386 | target = 14A630141D3293C700809B3F /* TestHost */; 387 | targetProxy = 14F0C1991D32A160007DCDDB /* PBXContainerItemProxy */; 388 | }; 389 | /* End PBXTargetDependency section */ 390 | 391 | /* Begin XCBuildConfiguration section */ 392 | 140F19701A49D79500B0016A /* Debug */ = { 393 | isa = XCBuildConfiguration; 394 | baseConfigurationReference = 148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */; 395 | buildSettings = { 396 | }; 397 | name = Debug; 398 | }; 399 | 140F19711A49D79500B0016A /* Release */ = { 400 | isa = XCBuildConfiguration; 401 | baseConfigurationReference = 148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */; 402 | buildSettings = { 403 | }; 404 | name = Release; 405 | }; 406 | 140F19731A49D79500B0016A /* Debug */ = { 407 | isa = XCBuildConfiguration; 408 | baseConfigurationReference = 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */; 409 | buildSettings = { 410 | }; 411 | name = Debug; 412 | }; 413 | 140F19741A49D79500B0016A /* Release */ = { 414 | isa = XCBuildConfiguration; 415 | baseConfigurationReference = 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */; 416 | buildSettings = { 417 | }; 418 | name = Release; 419 | }; 420 | 140F19761A49D79500B0016A /* Debug */ = { 421 | isa = XCBuildConfiguration; 422 | baseConfigurationReference = 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */; 423 | buildSettings = { 424 | }; 425 | name = Debug; 426 | }; 427 | 140F19771A49D79500B0016A /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */; 430 | buildSettings = { 431 | }; 432 | name = Release; 433 | }; 434 | 14A630251D3293C700809B3F /* Debug */ = { 435 | isa = XCBuildConfiguration; 436 | baseConfigurationReference = 14F0C1981D329832007DCDDB /* TestHost.xcconfig */; 437 | buildSettings = { 438 | }; 439 | name = Debug; 440 | }; 441 | 14A630261D3293C700809B3F /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | baseConfigurationReference = 14F0C1981D329832007DCDDB /* TestHost.xcconfig */; 444 | buildSettings = { 445 | }; 446 | name = Release; 447 | }; 448 | /* End XCBuildConfiguration section */ 449 | 450 | /* Begin XCConfigurationList section */ 451 | 140F19561A49D79400B0016A /* Build configuration list for PBXProject "KeychainAccess" */ = { 452 | isa = XCConfigurationList; 453 | buildConfigurations = ( 454 | 140F19701A49D79500B0016A /* Debug */, 455 | 140F19711A49D79500B0016A /* Release */, 456 | ); 457 | defaultConfigurationIsVisible = 0; 458 | defaultConfigurationName = Release; 459 | }; 460 | 140F19721A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccess" */ = { 461 | isa = XCConfigurationList; 462 | buildConfigurations = ( 463 | 140F19731A49D79500B0016A /* Debug */, 464 | 140F19741A49D79500B0016A /* Release */, 465 | ); 466 | defaultConfigurationIsVisible = 0; 467 | defaultConfigurationName = Release; 468 | }; 469 | 140F19751A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccessTests" */ = { 470 | isa = XCConfigurationList; 471 | buildConfigurations = ( 472 | 140F19761A49D79500B0016A /* Debug */, 473 | 140F19771A49D79500B0016A /* Release */, 474 | ); 475 | defaultConfigurationIsVisible = 0; 476 | defaultConfigurationName = Release; 477 | }; 478 | 14A630241D3293C700809B3F /* Build configuration list for PBXNativeTarget "TestHost" */ = { 479 | isa = XCConfigurationList; 480 | buildConfigurations = ( 481 | 14A630251D3293C700809B3F /* Debug */, 482 | 14A630261D3293C700809B3F /* Release */, 483 | ); 484 | defaultConfigurationIsVisible = 0; 485 | defaultConfigurationName = Release; 486 | }; 487 | /* End XCConfigurationList section */ 488 | }; 489 | rootObject = 140F19531A49D79400B0016A /* Project object */; 490 | } 491 | -------------------------------------------------------------------------------- /Lib/KeychainAccess.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Lib/KeychainAccess.xcodeproj/xcshareddata/xcschemes/KeychainAccess.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 51 | 52 | 53 | 54 | 56 | 62 | 63 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 86 | 87 | 93 | 94 | 95 | 96 | 102 | 103 | 109 | 110 | 111 | 112 | 114 | 115 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /Lib/KeychainAccess.xcodeproj/xcshareddata/xcschemes/TestHost.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Lib/KeychainAccess/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 4.2.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Lib/KeychainAccess/KeychainAccess.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeychainAccess.h 3 | // KeychainAccess 4 | // 5 | // Created by kishikawa katsumi on 2014/12/24. 6 | // Copyright (c) 2014 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | FOUNDATION_EXPORT double KeychainAccessVersionNumber; 29 | FOUNDATION_EXPORT const unsigned char KeychainAccessVersionString[]; 30 | -------------------------------------------------------------------------------- /Lib/KeychainAccessTests/EnumTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EnumTests.swift 3 | // KeychainAccessTests 4 | // 5 | // Created by kishikawa katsumi on 10/12/15. 6 | // Copyright © 2015 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import XCTest 27 | import KeychainAccess 28 | 29 | class EnumTests: XCTestCase { 30 | override func setUp() { 31 | super.setUp() 32 | } 33 | 34 | override func tearDown() { 35 | super.tearDown() 36 | } 37 | 38 | func testItemClass() { 39 | do { 40 | let itemClass = ItemClass(rawValue: kSecClassGenericPassword as String) 41 | XCTAssertEqual(itemClass, .genericPassword) 42 | XCTAssertEqual(itemClass?.description, "GenericPassword") 43 | } 44 | do { 45 | let itemClass = ItemClass(rawValue: kSecClassInternetPassword as String) 46 | XCTAssertEqual(itemClass, .internetPassword) 47 | XCTAssertEqual(itemClass?.description, "InternetPassword") 48 | } 49 | do { 50 | let itemClass = ItemClass(rawValue: kSecClassCertificate as String) 51 | XCTAssertNil(itemClass) 52 | } 53 | do { 54 | let itemClass = ItemClass(rawValue: kSecClassKey as String) 55 | XCTAssertNil(itemClass) 56 | } 57 | do { 58 | let itemClass = ItemClass(rawValue: kSecClassIdentity as String) 59 | XCTAssertNil(itemClass) 60 | } 61 | } 62 | 63 | func testProtocolType() { 64 | do { 65 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTP as String) 66 | XCTAssertEqual(protocolType, .ftp) 67 | XCTAssertEqual(protocolType?.description, "FTP") 68 | } 69 | do { 70 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPAccount as String) 71 | XCTAssertEqual(protocolType, .ftpAccount) 72 | XCTAssertEqual(protocolType?.description, "FTPAccount") 73 | } 74 | do { 75 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTP as String) 76 | XCTAssertEqual(protocolType, .http) 77 | XCTAssertEqual(protocolType?.description, "HTTP") 78 | } 79 | do { 80 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRC as String) 81 | XCTAssertEqual(protocolType, .irc) 82 | XCTAssertEqual(protocolType?.description, "IRC") 83 | } 84 | do { 85 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTP as String) 86 | XCTAssertEqual(protocolType, .nntp) 87 | XCTAssertEqual(protocolType?.description, "NNTP") 88 | } 89 | do { 90 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3 as String) 91 | XCTAssertEqual(protocolType, .pop3) 92 | XCTAssertEqual(protocolType?.description, "POP3") 93 | } 94 | do { 95 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMTP as String) 96 | XCTAssertEqual(protocolType, .smtp) 97 | XCTAssertEqual(protocolType?.description, "SMTP") 98 | } 99 | do { 100 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolSOCKS as String) 101 | XCTAssertEqual(protocolType, .socks) 102 | XCTAssertEqual(protocolType?.description, "SOCKS") 103 | } 104 | do { 105 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAP as String) 106 | XCTAssertEqual(protocolType, .imap) 107 | XCTAssertEqual(protocolType?.description, "IMAP") 108 | } 109 | do { 110 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAP as String) 111 | XCTAssertEqual(protocolType, .ldap) 112 | XCTAssertEqual(protocolType?.description, "LDAP") 113 | } 114 | do { 115 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolAppleTalk as String) 116 | XCTAssertEqual(protocolType, .appleTalk) 117 | XCTAssertEqual(protocolType?.description, "AppleTalk") 118 | } 119 | do { 120 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolAFP as String) 121 | XCTAssertEqual(protocolType, .afp) 122 | XCTAssertEqual(protocolType?.description, "AFP") 123 | } 124 | do { 125 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnet as String) 126 | XCTAssertEqual(protocolType, .telnet) 127 | XCTAssertEqual(protocolType?.description, "Telnet") 128 | } 129 | do { 130 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolSSH as String) 131 | XCTAssertEqual(protocolType, .ssh) 132 | XCTAssertEqual(protocolType?.description, "SSH") 133 | } 134 | do { 135 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPS as String) 136 | XCTAssertEqual(protocolType, .ftps) 137 | XCTAssertEqual(protocolType?.description, "FTPS") 138 | } 139 | do { 140 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPS as String) 141 | XCTAssertEqual(protocolType, .https) 142 | XCTAssertEqual(protocolType?.description, "HTTPS") 143 | } 144 | do { 145 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPProxy as String) 146 | XCTAssertEqual(protocolType, .httpProxy) 147 | XCTAssertEqual(protocolType?.description, "HTTPProxy") 148 | } 149 | do { 150 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPSProxy as String) 151 | XCTAssertEqual(protocolType, .httpsProxy) 152 | XCTAssertEqual(protocolType?.description, "HTTPSProxy") 153 | } 154 | do { 155 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPProxy as String) 156 | XCTAssertEqual(protocolType, .ftpProxy) 157 | XCTAssertEqual(protocolType?.description, "FTPProxy") 158 | } 159 | do { 160 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMB as String) 161 | XCTAssertEqual(protocolType, .smb) 162 | XCTAssertEqual(protocolType?.description, "SMB") 163 | } 164 | do { 165 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSP as String) 166 | XCTAssertEqual(protocolType, .rtsp) 167 | XCTAssertEqual(protocolType?.description, "RTSP") 168 | } 169 | do { 170 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSPProxy as String) 171 | XCTAssertEqual(protocolType, .rtspProxy) 172 | XCTAssertEqual(protocolType?.description, "RTSPProxy") 173 | } 174 | do { 175 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolDAAP as String) 176 | XCTAssertEqual(protocolType, .daap) 177 | XCTAssertEqual(protocolType?.description, "DAAP") 178 | } 179 | do { 180 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolEPPC as String) 181 | XCTAssertEqual(protocolType, .eppc) 182 | XCTAssertEqual(protocolType?.description, "EPPC") 183 | } 184 | do { 185 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolIPP as String) 186 | XCTAssertEqual(protocolType, .ipp) 187 | XCTAssertEqual(protocolType?.description, "IPP") 188 | } 189 | do { 190 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTPS as String) 191 | XCTAssertEqual(protocolType, .nntps) 192 | XCTAssertEqual(protocolType?.description, "NNTPS") 193 | } 194 | do { 195 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAPS as String) 196 | XCTAssertEqual(protocolType, .ldaps) 197 | XCTAssertEqual(protocolType?.description, "LDAPS") 198 | } 199 | do { 200 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnetS as String) 201 | XCTAssertEqual(protocolType, .telnetS) 202 | XCTAssertEqual(protocolType?.description, "TelnetS") 203 | } 204 | do { 205 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAPS as String) 206 | XCTAssertEqual(protocolType, .imaps) 207 | XCTAssertEqual(protocolType?.description, "IMAPS") 208 | } 209 | do { 210 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRCS as String) 211 | XCTAssertEqual(protocolType, .ircs) 212 | XCTAssertEqual(protocolType?.description, "IRCS") 213 | } 214 | do { 215 | let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3S as String) 216 | XCTAssertEqual(protocolType, .pop3S) 217 | XCTAssertEqual(protocolType?.description, "POP3S") 218 | } 219 | } 220 | 221 | func testAuthenticationType() { 222 | do { 223 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeNTLM as String) 224 | XCTAssertEqual(authenticationType, .ntlm) 225 | XCTAssertEqual(authenticationType?.description, "NTLM") 226 | } 227 | do { 228 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeMSN as String) 229 | XCTAssertEqual(authenticationType, .msn) 230 | XCTAssertEqual(authenticationType?.description, "MSN") 231 | } 232 | do { 233 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDPA as String) 234 | XCTAssertEqual(authenticationType, .dpa) 235 | XCTAssertEqual(authenticationType?.description, "DPA") 236 | } 237 | do { 238 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeRPA as String) 239 | XCTAssertEqual(authenticationType, .rpa) 240 | XCTAssertEqual(authenticationType?.description, "RPA") 241 | } 242 | do { 243 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPBasic as String) 244 | XCTAssertEqual(authenticationType, .httpBasic) 245 | XCTAssertEqual(authenticationType?.description, "HTTPBasic") 246 | } 247 | do { 248 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPDigest as String) 249 | XCTAssertEqual(authenticationType, .httpDigest) 250 | XCTAssertEqual(authenticationType?.description, "HTTPDigest") 251 | } 252 | do { 253 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTMLForm as String) 254 | XCTAssertEqual(authenticationType, .htmlForm) 255 | XCTAssertEqual(authenticationType?.description, "HTMLForm") 256 | } 257 | do { 258 | let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDefault as String) 259 | XCTAssertEqual(authenticationType, .default) 260 | XCTAssertEqual(authenticationType?.description, "Default") 261 | } 262 | } 263 | 264 | func testAccessibility() { 265 | guard #available(macOS 10.10, *) else { 266 | return 267 | } 268 | do { 269 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlocked as String) 270 | XCTAssertEqual(accessibility, .whenUnlocked) 271 | XCTAssertEqual(accessibility?.description, "WhenUnlocked") 272 | } 273 | do { 274 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlock as String) 275 | XCTAssertEqual(accessibility, .afterFirstUnlock) 276 | XCTAssertEqual(accessibility?.description, "AfterFirstUnlock") 277 | } 278 | #if !targetEnvironment(macCatalyst) 279 | do { 280 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlways as String) 281 | XCTAssertEqual(accessibility, .always) 282 | XCTAssertEqual(accessibility?.description, "Always") 283 | } 284 | #endif 285 | do { 286 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly as String) 287 | XCTAssertEqual(accessibility, .whenPasscodeSetThisDeviceOnly) 288 | XCTAssertEqual(accessibility?.description, "WhenPasscodeSetThisDeviceOnly") 289 | } 290 | do { 291 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlockedThisDeviceOnly as String) 292 | XCTAssertEqual(accessibility, .whenUnlockedThisDeviceOnly) 293 | XCTAssertEqual(accessibility?.description, "WhenUnlockedThisDeviceOnly") 294 | } 295 | do { 296 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String) 297 | XCTAssertEqual(accessibility, .afterFirstUnlockThisDeviceOnly) 298 | XCTAssertEqual(accessibility?.description, "AfterFirstUnlockThisDeviceOnly") 299 | } 300 | #if !targetEnvironment(macCatalyst) 301 | do { 302 | let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlwaysThisDeviceOnly as String) 303 | XCTAssertEqual(accessibility, .alwaysThisDeviceOnly) 304 | XCTAssertEqual(accessibility?.description, "AlwaysThisDeviceOnly") 305 | } 306 | #endif 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /Lib/KeychainAccessTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Lib/KeychainAccessTests/SharedCredentialTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SharedCredentialTests.swift 3 | // KeychainAccessTests 4 | // 5 | // Created by kishikawa katsumi on 10/12/15. 6 | // Copyright © 2015 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import XCTest 27 | import KeychainAccess 28 | 29 | class SharedCredentialTests: XCTestCase { 30 | override func setUp() { 31 | super.setUp() 32 | } 33 | 34 | override func tearDown() { 35 | super.tearDown() 36 | } 37 | 38 | func testGetSharedPassword() { 39 | do { 40 | let expectation = self.expectation(description: "getSharedPassword") 41 | 42 | let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https) 43 | 44 | keychain.getSharedPassword("kishikawakatsumi") { (password, error) -> () in 45 | XCTAssertNil(password) 46 | XCTAssertNotNil(error) 47 | expectation.fulfill() 48 | } 49 | 50 | waitForExpectations(timeout: 10.0, handler: nil) 51 | } 52 | do { 53 | let expectation = self.expectation(description: "getSharedPassword") 54 | 55 | let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https) 56 | 57 | keychain.getSharedPassword { (account, password, error) -> () in 58 | XCTAssertNil(account) 59 | XCTAssertNil(password) 60 | XCTAssertNotNil(error) 61 | expectation.fulfill() 62 | } 63 | 64 | waitForExpectations(timeout: 10.0, handler: nil) 65 | } 66 | 67 | } 68 | 69 | func testGeneratePassword() { 70 | do { 71 | var passwords = Set() 72 | for _ in 0...100_000 { 73 | let password = Keychain.generatePassword() 74 | 75 | #if swift(>=4.2) 76 | XCTAssertEqual(password.count, "xxx-xxx-xxx-xxx".count) 77 | #else 78 | XCTAssertEqual(password.characters.count, "xxx-xxx-xxx-xxx".characters.count) 79 | #endif 80 | XCTAssertFalse(passwords.contains(password)) 81 | 82 | passwords.insert(password) 83 | } 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/EnumTests.swift: -------------------------------------------------------------------------------- 1 | ../../KeychainAccessTests/EnumTests.swift -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/ErrorTypeTests.swift: -------------------------------------------------------------------------------- 1 | ../../KeychainAccessTests/ErrorTypeTests.swift -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/KeychainAccessTests-MacCatalyst/KeychainAccessTests.swift: -------------------------------------------------------------------------------- 1 | ../../KeychainAccessTests/KeychainAccessTests.swift -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 14A98C4F235D284F00BBB893 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C4E235D284F00BBB893 /* AppDelegate.swift */; }; 11 | 14A98C51235D284F00BBB893 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C50235D284F00BBB893 /* SceneDelegate.swift */; }; 12 | 14A98C53235D284F00BBB893 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C52235D284F00BBB893 /* ViewController.swift */; }; 13 | 14A98C56235D284F00BBB893 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14A98C54235D284F00BBB893 /* Main.storyboard */; }; 14 | 14A98C58235D285000BBB893 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14A98C57235D285000BBB893 /* Assets.xcassets */; }; 15 | 14A98C5B235D285000BBB893 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14A98C59235D285000BBB893 /* LaunchScreen.storyboard */; }; 16 | 14A98C65235D286B00BBB893 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A98C64235D286B00BBB893 /* KeychainAccess.framework */; }; 17 | 14A98C66235D286B00BBB893 /* KeychainAccess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14A98C64235D286B00BBB893 /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 14A98C88235D2AFA00BBB893 /* ErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C84235D2AFA00BBB893 /* ErrorTypeTests.swift */; }; 19 | 14A98C8A235D2AFA00BBB893 /* KeychainAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C86235D2AFA00BBB893 /* KeychainAccessTests.swift */; }; 20 | 14A98C8B235D2AFA00BBB893 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A98C87235D2AFA00BBB893 /* EnumTests.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 14A98C82235D293300BBB893 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 14A98C43235D284F00BBB893 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 14A98C4A235D284F00BBB893; 29 | remoteInfo = "TestHost-MacCatalyst"; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXCopyFilesBuildPhase section */ 34 | 14A98C67235D286B00BBB893 /* Embed Frameworks */ = { 35 | isa = PBXCopyFilesBuildPhase; 36 | buildActionMask = 2147483647; 37 | dstPath = ""; 38 | dstSubfolderSpec = 10; 39 | files = ( 40 | 14A98C66235D286B00BBB893 /* KeychainAccess.framework in Embed Frameworks */, 41 | ); 42 | name = "Embed Frameworks"; 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXCopyFilesBuildPhase section */ 46 | 47 | /* Begin PBXFileReference section */ 48 | 14A98C4B235D284F00BBB893 /* TestHost-MacCatalyst.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TestHost-MacCatalyst.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 14A98C4E235D284F00BBB893 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 50 | 14A98C50235D284F00BBB893 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 51 | 14A98C52235D284F00BBB893 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 52 | 14A98C55235D284F00BBB893 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 14A98C57235D285000BBB893 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 14A98C5A235D285000BBB893 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 14A98C5C235D285000BBB893 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 14A98C62235D286500BBB893 /* TestHost-MacCatalyst.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "TestHost-MacCatalyst.entitlements"; sourceTree = ""; }; 57 | 14A98C64235D286B00BBB893 /* KeychainAccess.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KeychainAccess.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 14A98C7A235D292000BBB893 /* KeychainAccessTests-MacCatalyst.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "KeychainAccessTests-MacCatalyst.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 14A98C7E235D292000BBB893 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | 14A98C84235D2AFA00BBB893 /* ErrorTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorTypeTests.swift; sourceTree = ""; }; 61 | 14A98C86235D2AFA00BBB893 /* KeychainAccessTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainAccessTests.swift; sourceTree = ""; }; 62 | 14A98C87235D2AFA00BBB893 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 14A98C48235D284F00BBB893 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | 14A98C65235D286B00BBB893 /* KeychainAccess.framework in Frameworks */, 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | 14A98C77235D292000BBB893 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 14A98C42235D284F00BBB893 = { 85 | isa = PBXGroup; 86 | children = ( 87 | 14A98C4D235D284F00BBB893 /* TestHost-MacCatalyst */, 88 | 14A98C7B235D292000BBB893 /* KeychainAccessTests-MacCatalyst */, 89 | 14A98C4C235D284F00BBB893 /* Products */, 90 | 14A98C63235D286B00BBB893 /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 14A98C4C235D284F00BBB893 /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 14A98C4B235D284F00BBB893 /* TestHost-MacCatalyst.app */, 98 | 14A98C7A235D292000BBB893 /* KeychainAccessTests-MacCatalyst.xctest */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | 14A98C4D235D284F00BBB893 /* TestHost-MacCatalyst */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 14A98C4E235D284F00BBB893 /* AppDelegate.swift */, 107 | 14A98C50235D284F00BBB893 /* SceneDelegate.swift */, 108 | 14A98C52235D284F00BBB893 /* ViewController.swift */, 109 | 14A98C54235D284F00BBB893 /* Main.storyboard */, 110 | 14A98C59235D285000BBB893 /* LaunchScreen.storyboard */, 111 | 14A98C57235D285000BBB893 /* Assets.xcassets */, 112 | 14A98C5C235D285000BBB893 /* Info.plist */, 113 | 14A98C62235D286500BBB893 /* TestHost-MacCatalyst.entitlements */, 114 | ); 115 | path = "TestHost-MacCatalyst"; 116 | sourceTree = ""; 117 | }; 118 | 14A98C63235D286B00BBB893 /* Frameworks */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 14A98C64235D286B00BBB893 /* KeychainAccess.framework */, 122 | ); 123 | name = Frameworks; 124 | sourceTree = ""; 125 | }; 126 | 14A98C7B235D292000BBB893 /* KeychainAccessTests-MacCatalyst */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 14A98C86235D2AFA00BBB893 /* KeychainAccessTests.swift */, 130 | 14A98C87235D2AFA00BBB893 /* EnumTests.swift */, 131 | 14A98C84235D2AFA00BBB893 /* ErrorTypeTests.swift */, 132 | 14A98C7E235D292000BBB893 /* Info.plist */, 133 | ); 134 | path = "KeychainAccessTests-MacCatalyst"; 135 | sourceTree = ""; 136 | }; 137 | /* End PBXGroup section */ 138 | 139 | /* Begin PBXNativeTarget section */ 140 | 14A98C4A235D284F00BBB893 /* TestHost-MacCatalyst */ = { 141 | isa = PBXNativeTarget; 142 | buildConfigurationList = 14A98C5F235D285000BBB893 /* Build configuration list for PBXNativeTarget "TestHost-MacCatalyst" */; 143 | buildPhases = ( 144 | 14A98C47235D284F00BBB893 /* Sources */, 145 | 14A98C48235D284F00BBB893 /* Frameworks */, 146 | 14A98C49235D284F00BBB893 /* Resources */, 147 | 14A98C67235D286B00BBB893 /* Embed Frameworks */, 148 | ); 149 | buildRules = ( 150 | ); 151 | dependencies = ( 152 | ); 153 | name = "TestHost-MacCatalyst"; 154 | productName = "TestHost-MacCatalyst"; 155 | productReference = 14A98C4B235D284F00BBB893 /* TestHost-MacCatalyst.app */; 156 | productType = "com.apple.product-type.application"; 157 | }; 158 | 14A98C79235D292000BBB893 /* KeychainAccessTests-MacCatalyst */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 14A98C7F235D292000BBB893 /* Build configuration list for PBXNativeTarget "KeychainAccessTests-MacCatalyst" */; 161 | buildPhases = ( 162 | 14A98C76235D292000BBB893 /* Sources */, 163 | 14A98C77235D292000BBB893 /* Frameworks */, 164 | 14A98C78235D292000BBB893 /* Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | 14A98C83235D293300BBB893 /* PBXTargetDependency */, 170 | ); 171 | name = "KeychainAccessTests-MacCatalyst"; 172 | productName = "KeychainAccessTests-MacCatalyst"; 173 | productReference = 14A98C7A235D292000BBB893 /* KeychainAccessTests-MacCatalyst.xctest */; 174 | productType = "com.apple.product-type.bundle.unit-test"; 175 | }; 176 | /* End PBXNativeTarget section */ 177 | 178 | /* Begin PBXProject section */ 179 | 14A98C43235D284F00BBB893 /* Project object */ = { 180 | isa = PBXProject; 181 | attributes = { 182 | LastSwiftUpdateCheck = 1100; 183 | LastUpgradeCheck = 1200; 184 | ORGANIZATIONNAME = "Kishikawa Katsumi"; 185 | TargetAttributes = { 186 | 14A98C4A235D284F00BBB893 = { 187 | CreatedOnToolsVersion = 11.0; 188 | }; 189 | 14A98C79235D292000BBB893 = { 190 | CreatedOnToolsVersion = 11.0; 191 | LastSwiftMigration = 1100; 192 | TestTargetID = 14A98C4A235D284F00BBB893; 193 | }; 194 | }; 195 | }; 196 | buildConfigurationList = 14A98C46235D284F00BBB893 /* Build configuration list for PBXProject "TestHost-MacCatalyst" */; 197 | compatibilityVersion = "Xcode 9.3"; 198 | developmentRegion = en; 199 | hasScannedForEncodings = 0; 200 | knownRegions = ( 201 | en, 202 | Base, 203 | ); 204 | mainGroup = 14A98C42235D284F00BBB893; 205 | productRefGroup = 14A98C4C235D284F00BBB893 /* Products */; 206 | projectDirPath = ""; 207 | projectRoot = ""; 208 | targets = ( 209 | 14A98C4A235D284F00BBB893 /* TestHost-MacCatalyst */, 210 | 14A98C79235D292000BBB893 /* KeychainAccessTests-MacCatalyst */, 211 | ); 212 | }; 213 | /* End PBXProject section */ 214 | 215 | /* Begin PBXResourcesBuildPhase section */ 216 | 14A98C49235D284F00BBB893 /* Resources */ = { 217 | isa = PBXResourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 14A98C5B235D285000BBB893 /* LaunchScreen.storyboard in Resources */, 221 | 14A98C58235D285000BBB893 /* Assets.xcassets in Resources */, 222 | 14A98C56235D284F00BBB893 /* Main.storyboard in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | 14A98C78235D292000BBB893 /* Resources */ = { 227 | isa = PBXResourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXResourcesBuildPhase section */ 234 | 235 | /* Begin PBXSourcesBuildPhase section */ 236 | 14A98C47235D284F00BBB893 /* Sources */ = { 237 | isa = PBXSourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 14A98C53235D284F00BBB893 /* ViewController.swift in Sources */, 241 | 14A98C4F235D284F00BBB893 /* AppDelegate.swift in Sources */, 242 | 14A98C51235D284F00BBB893 /* SceneDelegate.swift in Sources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | 14A98C76235D292000BBB893 /* Sources */ = { 247 | isa = PBXSourcesBuildPhase; 248 | buildActionMask = 2147483647; 249 | files = ( 250 | 14A98C88235D2AFA00BBB893 /* ErrorTypeTests.swift in Sources */, 251 | 14A98C8B235D2AFA00BBB893 /* EnumTests.swift in Sources */, 252 | 14A98C8A235D2AFA00BBB893 /* KeychainAccessTests.swift in Sources */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | /* End PBXSourcesBuildPhase section */ 257 | 258 | /* Begin PBXTargetDependency section */ 259 | 14A98C83235D293300BBB893 /* PBXTargetDependency */ = { 260 | isa = PBXTargetDependency; 261 | target = 14A98C4A235D284F00BBB893 /* TestHost-MacCatalyst */; 262 | targetProxy = 14A98C82235D293300BBB893 /* PBXContainerItemProxy */; 263 | }; 264 | /* End PBXTargetDependency section */ 265 | 266 | /* Begin PBXVariantGroup section */ 267 | 14A98C54235D284F00BBB893 /* Main.storyboard */ = { 268 | isa = PBXVariantGroup; 269 | children = ( 270 | 14A98C55235D284F00BBB893 /* Base */, 271 | ); 272 | name = Main.storyboard; 273 | sourceTree = ""; 274 | }; 275 | 14A98C59235D285000BBB893 /* LaunchScreen.storyboard */ = { 276 | isa = PBXVariantGroup; 277 | children = ( 278 | 14A98C5A235D285000BBB893 /* Base */, 279 | ); 280 | name = LaunchScreen.storyboard; 281 | sourceTree = ""; 282 | }; 283 | /* End PBXVariantGroup section */ 284 | 285 | /* Begin XCBuildConfiguration section */ 286 | 14A98C5D235D285000BBB893 /* Debug */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ALWAYS_SEARCH_USER_PATHS = NO; 290 | CLANG_ANALYZER_NONNULL = YES; 291 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 293 | CLANG_CXX_LIBRARY = "libc++"; 294 | CLANG_ENABLE_MODULES = YES; 295 | CLANG_ENABLE_OBJC_ARC = YES; 296 | CLANG_ENABLE_OBJC_WEAK = YES; 297 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 298 | CLANG_WARN_BOOL_CONVERSION = YES; 299 | CLANG_WARN_COMMA = YES; 300 | CLANG_WARN_CONSTANT_CONVERSION = YES; 301 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 303 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 304 | CLANG_WARN_EMPTY_BODY = YES; 305 | CLANG_WARN_ENUM_CONVERSION = YES; 306 | CLANG_WARN_INFINITE_RECURSION = YES; 307 | CLANG_WARN_INT_CONVERSION = YES; 308 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 309 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 310 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 312 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 313 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 314 | CLANG_WARN_STRICT_PROTOTYPES = YES; 315 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 316 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | COPY_PHASE_STRIP = NO; 320 | DEBUG_INFORMATION_FORMAT = dwarf; 321 | ENABLE_STRICT_OBJC_MSGSEND = YES; 322 | ENABLE_TESTABILITY = YES; 323 | GCC_C_LANGUAGE_STANDARD = gnu11; 324 | GCC_DYNAMIC_NO_PIC = NO; 325 | GCC_NO_COMMON_BLOCKS = YES; 326 | GCC_OPTIMIZATION_LEVEL = 0; 327 | GCC_PREPROCESSOR_DEFINITIONS = ( 328 | "DEBUG=1", 329 | "$(inherited)", 330 | ); 331 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 332 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 333 | GCC_WARN_UNDECLARED_SELECTOR = YES; 334 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 335 | GCC_WARN_UNUSED_FUNCTION = YES; 336 | GCC_WARN_UNUSED_VARIABLE = YES; 337 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 338 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 339 | MTL_FAST_MATH = YES; 340 | ONLY_ACTIVE_ARCH = YES; 341 | SDKROOT = iphoneos; 342 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 343 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 344 | }; 345 | name = Debug; 346 | }; 347 | 14A98C5E235D285000BBB893 /* Release */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | ALWAYS_SEARCH_USER_PATHS = NO; 351 | CLANG_ANALYZER_NONNULL = YES; 352 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_ENABLE_OBJC_WEAK = YES; 358 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 359 | CLANG_WARN_BOOL_CONVERSION = YES; 360 | CLANG_WARN_COMMA = YES; 361 | CLANG_WARN_CONSTANT_CONVERSION = YES; 362 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 363 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 364 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 365 | CLANG_WARN_EMPTY_BODY = YES; 366 | CLANG_WARN_ENUM_CONVERSION = YES; 367 | CLANG_WARN_INFINITE_RECURSION = YES; 368 | CLANG_WARN_INT_CONVERSION = YES; 369 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 370 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 371 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 373 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 374 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 375 | CLANG_WARN_STRICT_PROTOTYPES = YES; 376 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 377 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | COPY_PHASE_STRIP = NO; 381 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 382 | ENABLE_NS_ASSERTIONS = NO; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | GCC_C_LANGUAGE_STANDARD = gnu11; 385 | GCC_NO_COMMON_BLOCKS = YES; 386 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 387 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 388 | GCC_WARN_UNDECLARED_SELECTOR = YES; 389 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 390 | GCC_WARN_UNUSED_FUNCTION = YES; 391 | GCC_WARN_UNUSED_VARIABLE = YES; 392 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 393 | MTL_ENABLE_DEBUG_INFO = NO; 394 | MTL_FAST_MATH = YES; 395 | SDKROOT = iphoneos; 396 | SWIFT_COMPILATION_MODE = wholemodule; 397 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 398 | VALIDATE_PRODUCT = YES; 399 | }; 400 | name = Release; 401 | }; 402 | 14A98C60235D285000BBB893 /* Debug */ = { 403 | isa = XCBuildConfiguration; 404 | buildSettings = { 405 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 406 | CODE_SIGN_ENTITLEMENTS = "TestHost-MacCatalyst/TestHost-MacCatalyst.entitlements"; 407 | CODE_SIGN_STYLE = Automatic; 408 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; 409 | DEVELOPMENT_TEAM = 27AEDK3C9F; 410 | INFOPLIST_FILE = "TestHost-MacCatalyst/Info.plist"; 411 | LD_RUNPATH_SEARCH_PATHS = ( 412 | "$(inherited)", 413 | "@executable_path/Frameworks", 414 | ); 415 | PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | SUPPORTS_MACCATALYST = YES; 418 | SWIFT_VERSION = 5.0; 419 | TARGETED_DEVICE_FAMILY = "1,2"; 420 | }; 421 | name = Debug; 422 | }; 423 | 14A98C61235D285000BBB893 /* Release */ = { 424 | isa = XCBuildConfiguration; 425 | buildSettings = { 426 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 427 | CODE_SIGN_ENTITLEMENTS = "TestHost-MacCatalyst/TestHost-MacCatalyst.entitlements"; 428 | CODE_SIGN_STYLE = Automatic; 429 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; 430 | DEVELOPMENT_TEAM = 27AEDK3C9F; 431 | INFOPLIST_FILE = "TestHost-MacCatalyst/Info.plist"; 432 | LD_RUNPATH_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "@executable_path/Frameworks", 435 | ); 436 | PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst"; 437 | PRODUCT_NAME = "$(TARGET_NAME)"; 438 | SUPPORTS_MACCATALYST = YES; 439 | SWIFT_VERSION = 5.0; 440 | TARGETED_DEVICE_FAMILY = "1,2"; 441 | }; 442 | name = Release; 443 | }; 444 | 14A98C80235D292000BBB893 /* Debug */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | CLANG_ENABLE_MODULES = YES; 448 | CODE_SIGN_STYLE = Automatic; 449 | DEVELOPMENT_TEAM = 27AEDK3C9F; 450 | INFOPLIST_FILE = "KeychainAccessTests-MacCatalyst/Info.plist"; 451 | LD_RUNPATH_SEARCH_PATHS = ( 452 | "$(inherited)", 453 | "@executable_path/Frameworks", 454 | "@loader_path/Frameworks", 455 | ); 456 | PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccessTests-MacCatalyst"; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 459 | SWIFT_VERSION = 5.0; 460 | TARGETED_DEVICE_FAMILY = "1,2"; 461 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost-MacCatalyst.app/TestHost-MacCatalyst"; 462 | }; 463 | name = Debug; 464 | }; 465 | 14A98C81235D292000BBB893 /* Release */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | CLANG_ENABLE_MODULES = YES; 469 | CODE_SIGN_STYLE = Automatic; 470 | DEVELOPMENT_TEAM = 27AEDK3C9F; 471 | INFOPLIST_FILE = "KeychainAccessTests-MacCatalyst/Info.plist"; 472 | LD_RUNPATH_SEARCH_PATHS = ( 473 | "$(inherited)", 474 | "@executable_path/Frameworks", 475 | "@loader_path/Frameworks", 476 | ); 477 | PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.KeychainAccessTests-MacCatalyst"; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | SWIFT_VERSION = 5.0; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost-MacCatalyst.app/TestHost-MacCatalyst"; 482 | }; 483 | name = Release; 484 | }; 485 | /* End XCBuildConfiguration section */ 486 | 487 | /* Begin XCConfigurationList section */ 488 | 14A98C46235D284F00BBB893 /* Build configuration list for PBXProject "TestHost-MacCatalyst" */ = { 489 | isa = XCConfigurationList; 490 | buildConfigurations = ( 491 | 14A98C5D235D285000BBB893 /* Debug */, 492 | 14A98C5E235D285000BBB893 /* Release */, 493 | ); 494 | defaultConfigurationIsVisible = 0; 495 | defaultConfigurationName = Release; 496 | }; 497 | 14A98C5F235D285000BBB893 /* Build configuration list for PBXNativeTarget "TestHost-MacCatalyst" */ = { 498 | isa = XCConfigurationList; 499 | buildConfigurations = ( 500 | 14A98C60235D285000BBB893 /* Debug */, 501 | 14A98C61235D285000BBB893 /* Release */, 502 | ); 503 | defaultConfigurationIsVisible = 0; 504 | defaultConfigurationName = Release; 505 | }; 506 | 14A98C7F235D292000BBB893 /* Build configuration list for PBXNativeTarget "KeychainAccessTests-MacCatalyst" */ = { 507 | isa = XCConfigurationList; 508 | buildConfigurations = ( 509 | 14A98C80235D292000BBB893 /* Debug */, 510 | 14A98C81235D292000BBB893 /* Release */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | /* End XCConfigurationList section */ 516 | }; 517 | rootObject = 14A98C43235D284F00BBB893 /* Project object */; 518 | } 519 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst.xcodeproj/xcshareddata/xcschemes/TestHost-MacCatalyst.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TestHost-MacCatalyst 4 | // 5 | // Created by Kishikawa Katsumi on 2019/10/21. 6 | // Copyright © 2019 Kishikawa Katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | @UIApplicationMain 29 | class AppDelegate: UIResponder, UIApplicationDelegate { 30 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 31 | return true 32 | } 33 | 34 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 35 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // TestHost-MacCatalyst 4 | // 5 | // Created by Kishikawa Katsumi on 2019/10/21. 6 | // Copyright © 2019 Kishikawa Katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 29 | var window: UIWindow? 30 | } 31 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/TestHost-MacCatalyst.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | keychain-access-groups 10 | 11 | $(AppIdentifierPrefix)com.kishikawakatsumi.KeychainAccess.TestHost-MacCatalyst 12 | $(AppIdentifierPrefix)shared 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Lib/TestHost-MacCatalyst/TestHost-MacCatalyst/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TestHost-MacCatalyst 4 | // 5 | // Created by Kishikawa Katsumi on 2019/10/21. 6 | // Copyright © 2019 Kishikawa Katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | class ViewController: UIViewController { 29 | override func viewDidLoad() { 30 | super.viewDidLoad() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Lib/TestHost/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TestHost 4 | // 5 | // Created by kishikawa katsumi on 7/10/16. 6 | // Copyright © 2016 kishikawa katsumi. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #if os(macOS) 27 | import Cocoa 28 | 29 | @NSApplicationMain 30 | class AppDelegate: NSObject, NSApplicationDelegate { 31 | @IBOutlet weak var window: NSWindow! 32 | func applicationDidFinishLaunching(aNotification: NSNotification) {} 33 | } 34 | #else 35 | import UIKit 36 | 37 | @UIApplicationMain 38 | class AppDelegate: UIResponder, UIApplicationDelegate { 39 | var window: UIWindow? 40 | 41 | #if swift(>=4.2) 42 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 43 | return true 44 | } 45 | #else 46 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { 47 | return true 48 | } 49 | #endif 50 | } 51 | #endif 52 | -------------------------------------------------------------------------------- /Lib/TestHost/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Lib/TestHost/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIRequiresFullScreen 43 | 44 | NSPrincipalClass 45 | $(PRINCIPAL_CLASS) 46 | 47 | 48 | -------------------------------------------------------------------------------- /Lib/TestHost/TestHost.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | keychain-access-groups 6 | 7 | $(AppIdentifierPrefix)com.kishikawakatsumi.KeychainAccess.TestHost 8 | $(AppIdentifierPrefix)shared 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | // Package.swift 4 | // KeychainAccess 5 | // 6 | // Created by kishikawa katsumi on 2015/12/4. 7 | // Copyright (c) 2015 kishikawa katsumi. All rights reserved. 8 | // 9 | 10 | import PackageDescription 11 | 12 | let package = Package( 13 | name: "KeychainAccess", 14 | platforms: [ 15 | .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2) 16 | ], 17 | products: [ 18 | .library(name: "KeychainAccess", targets: ["KeychainAccess"]) 19 | ], 20 | targets: [ 21 | .target( 22 | name: "KeychainAccess", 23 | path: "Lib/KeychainAccess", 24 | linkerSettings: [.unsafeFlags(["-Xlinker", "-no_application_extension"])]) 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /Package@swift-5.3.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | // Package.swift 4 | // KeychainAccess 5 | // 6 | // Created by kishikawa katsumi on 2015/12/4. 7 | // Copyright (c) 2015 kishikawa katsumi. All rights reserved. 8 | // 9 | 10 | import PackageDescription 11 | 12 | let package = Package( 13 | name: "KeychainAccess", 14 | platforms: [ 15 | .macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2) 16 | ], 17 | products: [ 18 | .library(name: "KeychainAccess", targets: ["KeychainAccess"]) 19 | ], 20 | targets: [ 21 | .target( 22 | name: "KeychainAccess", 23 | path: "Lib/KeychainAccess", 24 | exclude: ["Info.plist"], 25 | linkerSettings: [.unsafeFlags(["-Xlinker", "-no_application_extension"])] 26 | ) 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeychainAccess 2 | 3 | [![Build Status](https://travis-ci.com/kishikawakatsumi/KeychainAccess.svg?branch=master)](https://travis-ci.com/kishikawakatsumi/KeychainAccess) 4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![SPM supported](https://img.shields.io/badge/SPM-supported-DE5C43.svg?style=flat)](https://swift.org/package-manager) 6 | [![Version](https://img.shields.io/cocoapods/v/KeychainAccess.svg)](http://cocoadocs.org/docsets/KeychainAccess) 7 | [![Platform](https://img.shields.io/cocoapods/p/KeychainAccess.svg)](http://cocoadocs.org/docsets/KeychainAccess) 8 | 9 | KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and macOS. Makes using Keychain APIs extremely easy and much more palatable to use in Swift. 10 | 11 | 12 | 13 | 14 | ## :bulb: Features 15 | 16 | - Simple interface 17 | - Support access group 18 | - [Support accessibility](#accessibility) 19 | - [Support iCloud sharing](#icloud_sharing) 20 | - **[Support TouchID and Keychain integration (iOS 8+)](#touch_id_integration)** 21 | - **[Support Shared Web Credentials (iOS 8+)](#shared_web_credentials)** 22 | - [Works on both iOS & macOS](#requirements) 23 | - [watchOS and tvOS are supported](#requirements) 24 | - **[Mac Catalyst is supported](#requirements)** 25 | - **[Swift 3, 4 and 5 compatible](#requirements)** 26 | 27 | ## :book: Usage 28 | 29 | ##### :eyes: See also: 30 | 31 | - [:link: iOS Example Project](https://github.com/kishikawakatsumi/KeychainAccess/tree/master/Examples/Example-iOS) 32 | 33 | ### :key: Basics 34 | 35 | #### Saving Application Password 36 | 37 | ```swift 38 | let keychain = Keychain(service: "com.example.github-token") 39 | keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 40 | ``` 41 | 42 | #### Saving Internet Password 43 | 44 | ```swift 45 | let keychain = Keychain(server: "https://github.com", protocolType: .https) 46 | keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 47 | ``` 48 | 49 | ### :key: Instantiation 50 | 51 | #### Create Keychain for Application Password 52 | 53 | ```swift 54 | let keychain = Keychain(service: "com.example.github-token") 55 | ``` 56 | 57 | ```swift 58 | let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared") 59 | ``` 60 | 61 | #### Create Keychain for Internet Password 62 | 63 | ```swift 64 | let keychain = Keychain(server: "https://github.com", protocolType: .https) 65 | ``` 66 | 67 | ```swift 68 | let keychain = Keychain(server: "https://github.com", protocolType: .https, authenticationType: .htmlForm) 69 | ``` 70 | 71 | ### :key: Adding an item 72 | 73 | #### subscripting 74 | 75 | ##### for String 76 | 77 | ```swift 78 | keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 79 | ``` 80 | 81 | ```swift 82 | keychain[string: "kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 83 | ``` 84 | 85 | ##### for NSData 86 | 87 | ```swift 88 | keychain[data: "secret"] = NSData(contentsOfFile: "secret.bin") 89 | ``` 90 | 91 | #### set method 92 | 93 | ```swift 94 | keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 95 | ``` 96 | 97 | #### error handling 98 | 99 | ```swift 100 | do { 101 | try keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 102 | } 103 | catch let error { 104 | print(error) 105 | } 106 | ``` 107 | 108 | ### :key: Obtaining an item 109 | 110 | #### subscripting 111 | 112 | ##### for String (If the value is NSData, attempt to convert to String) 113 | 114 | ```swift 115 | let token = keychain["kishikawakatsumi"] 116 | ``` 117 | 118 | ```swift 119 | let token = keychain[string: "kishikawakatsumi"] 120 | ``` 121 | 122 | ##### for NSData 123 | 124 | ```swift 125 | let secretData = keychain[data: "secret"] 126 | ``` 127 | 128 | #### get methods 129 | 130 | ##### as String 131 | 132 | ```swift 133 | let token = try? keychain.get("kishikawakatsumi") 134 | ``` 135 | 136 | ```swift 137 | let token = try? keychain.getString("kishikawakatsumi") 138 | ``` 139 | 140 | ##### as NSData 141 | 142 | ```swift 143 | let data = try? keychain.getData("kishikawakatsumi") 144 | ``` 145 | 146 | ### :key: Removing an item 147 | 148 | #### subscripting 149 | 150 | ```swift 151 | keychain["kishikawakatsumi"] = nil 152 | ``` 153 | 154 | #### remove method 155 | 156 | ```swift 157 | do { 158 | try keychain.remove("kishikawakatsumi") 159 | } catch let error { 160 | print("error: \(error)") 161 | } 162 | ``` 163 | 164 | ### :key: Set Label and Comment 165 | 166 | ```swift 167 | let keychain = Keychain(server: "https://github.com", protocolType: .https) 168 | do { 169 | try keychain 170 | .label("github.com (kishikawakatsumi)") 171 | .comment("github access token") 172 | .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 173 | } catch let error { 174 | print("error: \(error)") 175 | } 176 | ``` 177 | 178 | ### :key: Obtaining Other Attributes 179 | 180 | #### PersistentRef 181 | 182 | ```swift 183 | let keychain = Keychain() 184 | let persistentRef = keychain[attributes: "kishikawakatsumi"]?.persistentRef 185 | ... 186 | ``` 187 | 188 | #### Creation Date 189 | 190 | ```swift 191 | let keychain = Keychain() 192 | let creationDate = keychain[attributes: "kishikawakatsumi"]?.creationDate 193 | ... 194 | ``` 195 | 196 | #### All Attributes 197 | 198 | ```swift 199 | let keychain = Keychain() 200 | do { 201 | let attributes = try keychain.get("kishikawakatsumi") { $0 } 202 | print(attributes?.comment) 203 | print(attributes?.label) 204 | print(attributes?.creator) 205 | ... 206 | } catch let error { 207 | print("error: \(error)") 208 | } 209 | ``` 210 | 211 | ##### subscripting 212 | 213 | ```swift 214 | let keychain = Keychain() 215 | if let attributes = keychain[attributes: "kishikawakatsumi"] { 216 | print(attributes.comment) 217 | print(attributes.label) 218 | print(attributes.creator) 219 | } 220 | ``` 221 | 222 | ### :key: Configuration (Accessibility, Sharing, iCloud Sync) 223 | 224 | **Provides fluent interfaces** 225 | 226 | ```swift 227 | let keychain = Keychain(service: "com.example.github-token") 228 | .label("github.com (kishikawakatsumi)") 229 | .synchronizable(true) 230 | .accessibility(.afterFirstUnlock) 231 | ``` 232 | 233 | #### Accessibility 234 | 235 | ##### Default accessibility matches background application (=kSecAttrAccessibleAfterFirstUnlock) 236 | 237 | ```swift 238 | let keychain = Keychain(service: "com.example.github-token") 239 | ``` 240 | 241 | ##### For background application 242 | 243 | ###### Creating instance 244 | 245 | ```swift 246 | let keychain = Keychain(service: "com.example.github-token") 247 | .accessibility(.afterFirstUnlock) 248 | 249 | keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 250 | ``` 251 | 252 | ###### One-shot 253 | 254 | ```swift 255 | let keychain = Keychain(service: "com.example.github-token") 256 | 257 | do { 258 | try keychain 259 | .accessibility(.afterFirstUnlock) 260 | .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 261 | } catch let error { 262 | print("error: \(error)") 263 | } 264 | ``` 265 | 266 | ##### For foreground application 267 | 268 | ###### Creating instance 269 | 270 | ```swift 271 | let keychain = Keychain(service: "com.example.github-token") 272 | .accessibility(.whenUnlocked) 273 | 274 | keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 275 | ``` 276 | 277 | ###### One-shot 278 | 279 | ```swift 280 | let keychain = Keychain(service: "com.example.github-token") 281 | 282 | do { 283 | try keychain 284 | .accessibility(.whenUnlocked) 285 | .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 286 | } catch let error { 287 | print("error: \(error)") 288 | } 289 | ``` 290 | 291 | #### :couple: Sharing Keychain items 292 | 293 | ```swift 294 | let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared") 295 | ``` 296 | 297 | #### :arrows_counterclockwise: Synchronizing Keychain items with iCloud 298 | 299 | ###### Creating instance 300 | 301 | ```swift 302 | let keychain = Keychain(service: "com.example.github-token") 303 | .synchronizable(true) 304 | 305 | keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" 306 | ``` 307 | 308 | ###### One-shot 309 | 310 | ```swift 311 | let keychain = Keychain(service: "com.example.github-token") 312 | 313 | do { 314 | try keychain 315 | .synchronizable(true) 316 | .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 317 | } catch let error { 318 | print("error: \(error)") 319 | } 320 | ``` 321 | 322 | ### :cyclone: Touch ID (Face ID) integration 323 | 324 | **Any Operation that require authentication must be run in the background thread.** 325 | **If you run in the main thread, UI thread will lock for the system to try to display the authentication dialog.** 326 | 327 | **To use Face ID, add `NSFaceIDUsageDescription` key to your `Info.plist`** 328 | 329 | #### :closed_lock_with_key: Adding a Touch ID (Face ID) protected item 330 | 331 | If you want to store the Touch ID protected Keychain item, specify `accessibility` and `authenticationPolicy` attributes. 332 | 333 | ```swift 334 | let keychain = Keychain(service: "com.example.github-token") 335 | 336 | DispatchQueue.global().async { 337 | do { 338 | // Should be the secret invalidated when passcode is removed? If not then use `.WhenUnlocked` 339 | try keychain 340 | .accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny]) 341 | .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 342 | } catch let error { 343 | // Error handling if needed... 344 | } 345 | } 346 | ``` 347 | 348 | #### :closed_lock_with_key: Updating a Touch ID (Face ID) protected item 349 | 350 | The same way as when adding. 351 | 352 | **Do not run in the main thread if there is a possibility that the item you are trying to add already exists, and protected.** 353 | **Because updating protected items requires authentication.** 354 | 355 | Additionally, you want to show custom authentication prompt message when updating, specify an `authenticationPrompt` attribute. 356 | If the item not protected, the `authenticationPrompt` parameter just be ignored. 357 | 358 | ```swift 359 | let keychain = Keychain(service: "com.example.github-token") 360 | 361 | DispatchQueue.global().async { 362 | do { 363 | // Should be the secret invalidated when passcode is removed? If not then use `.WhenUnlocked` 364 | try keychain 365 | .accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny]) 366 | .authenticationPrompt("Authenticate to update your access token") 367 | .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") 368 | } catch let error { 369 | // Error handling if needed... 370 | } 371 | } 372 | ``` 373 | 374 | #### :closed_lock_with_key: Obtaining a Touch ID (Face ID) protected item 375 | 376 | 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. 377 | If you want to show custom authentication prompt message, specify an `authenticationPrompt` attribute. 378 | If the item not protected, the `authenticationPrompt` parameter just be ignored. 379 | 380 | ```swift 381 | let keychain = Keychain(service: "com.example.github-token") 382 | 383 | DispatchQueue.global().async { 384 | do { 385 | let password = try keychain 386 | .authenticationPrompt("Authenticate to login to server") 387 | .get("kishikawakatsumi") 388 | 389 | print("password: \(password)") 390 | } catch let error { 391 | // Error handling if needed... 392 | } 393 | } 394 | ``` 395 | 396 | #### :closed_lock_with_key: Removing a Touch ID (Face ID) protected item 397 | 398 | The same way as when you remove a normal item. 399 | There is no way to show Touch ID or passcode authentication when removing Keychain items. 400 | 401 | ```swift 402 | let keychain = Keychain(service: "com.example.github-token") 403 | 404 | do { 405 | try keychain.remove("kishikawakatsumi") 406 | } catch let error { 407 | // Error handling if needed... 408 | } 409 | ``` 410 | 411 | ### :key: Shared Web Credentials 412 | 413 | > 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. 414 | > 415 | 416 | ```swift 417 | let keychain = Keychain(server: "https://www.kishikawakatsumi.com", protocolType: .HTTPS) 418 | 419 | let username = "kishikawakatsumi@mac.com" 420 | 421 | // First, check the credential in the app's Keychain 422 | if let password = try? keychain.get(username) { 423 | // If found password in the Keychain, 424 | // then log into the server 425 | } else { 426 | // If not found password in the Keychain, 427 | // try to read from Shared Web Credentials 428 | keychain.getSharedPassword(username) { (password, error) -> () in 429 | if password != nil { 430 | // If found password in the Shared Web Credentials, 431 | // then log into the server 432 | // and save the password to the Keychain 433 | 434 | keychain[username] = password 435 | } else { 436 | // If not found password either in the Keychain also Shared Web Credentials, 437 | // prompt for username and password 438 | 439 | // Log into server 440 | 441 | // If the login is successful, 442 | // save the credentials to both the Keychain and the Shared Web Credentials. 443 | 444 | keychain[username] = inputPassword 445 | keychain.setSharedPassword(inputPassword, account: username) 446 | } 447 | } 448 | } 449 | ``` 450 | 451 | #### Request all associated domain's credentials 452 | 453 | ```swift 454 | Keychain.requestSharedWebCredential { (credentials, error) -> () in 455 | 456 | } 457 | ``` 458 | 459 | #### Generate strong random password 460 | 461 | Generate strong random password that is in the same format used by Safari autofill (xxx-xxx-xxx-xxx). 462 | 463 | ```swift 464 | let password = Keychain.generatePassword() // => Nhu-GKm-s3n-pMx 465 | ``` 466 | 467 | #### How to set up Shared Web Credentials 468 | 469 | > 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. 470 | > 471 | > 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. 472 | > 473 | > 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. 474 | 475 | **More details:** 476 | 477 | 478 | ### :mag: Debugging 479 | 480 | #### Display all stored items if print keychain object 481 | 482 | ```swift 483 | let keychain = Keychain(server: "https://github.com", protocolType: .https) 484 | print("\(keychain)") 485 | ``` 486 | 487 | ``` 488 | => 489 | [ 490 | [authenticationType: default, key: kishikawakatsumi, server: github.com, class: internetPassword, protocol: https] 491 | [authenticationType: default, key: hirohamada, server: github.com, class: internetPassword, protocol: https] 492 | [authenticationType: default, key: honeylemon, server: github.com, class: internetPassword, protocol: https] 493 | ] 494 | ``` 495 | 496 | #### Obtaining all stored keys 497 | 498 | ```swift 499 | let keychain = Keychain(server: "https://github.com", protocolType: .https) 500 | 501 | let keys = keychain.allKeys() 502 | for key in keys { 503 | print("key: \(key)") 504 | } 505 | ``` 506 | 507 | ``` 508 | => 509 | key: kishikawakatsumi 510 | key: hirohamada 511 | key: honeylemon 512 | ``` 513 | 514 | #### Obtaining all stored items 515 | 516 | ```swift 517 | let keychain = Keychain(server: "https://github.com", protocolType: .https) 518 | 519 | let items = keychain.allItems() 520 | for item in items { 521 | print("item: \(item)") 522 | } 523 | ``` 524 | 525 | ``` 526 | => 527 | item: [authenticationType: Default, key: kishikawakatsumi, server: github.com, class: InternetPassword, protocol: https] 528 | item: [authenticationType: Default, key: hirohamada, server: github.com, class: InternetPassword, protocol: https] 529 | item: [authenticationType: Default, key: honeylemon, server: github.com, class: InternetPassword, protocol: https] 530 | ``` 531 | 532 | ## Keychain sharing capability 533 | 534 | If you encounter the error below, you need to add an `Keychain.entitlements`. 535 | 536 | ``` 537 | OSStatus error:[-34018] Internal error when a required entitlement isn't present, client has neither application-identifier nor keychain-access-groups entitlements. 538 | ``` 539 | 540 | Screen Shot 2019-10-27 at 8 08 50 541 | 542 | 543 | 544 | ## Requirements 545 | 546 | | | OS | Swift | 547 | | ---------- | ---------------------------------------------------------- | ------------------ | 548 | | **v1.1.x** | iOS 7+, macOS 10.9+ | 1.1 | 549 | | **v1.2.x** | iOS 7+, macOS 10.9+ | 1.2 | 550 | | **v2.0.x** | iOS 7+, macOS 10.9+, watchOS 2+ | 2.0 | 551 | | **v2.1.x** | iOS 7+, macOS 10.9+, watchOS 2+ | 2.0 | 552 | | **v2.2.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1 | 553 | | **v2.3.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1, 2.2 | 554 | | **v2.4.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.2, 2.3 | 555 | | **v3.0.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 3.x | 556 | | **v3.1.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2 | 557 | | **v3.2.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2, 5.0 | 558 | | **v4.0.x** | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2, 5.1 | 559 | | **v4.1.x** | iOS 8+, macOS 10.9+, watchOS 3+, tvOS 9+, Mac Catalyst 13+ | 4.0, 4.1, 4.2, 5.1 | 560 | 561 | ## Installation 562 | 563 | ### CocoaPods 564 | 565 | KeychainAccess is available through [CocoaPods](http://cocoapods.org). To install 566 | it, simply add the following lines to your Podfile: 567 | 568 | ```ruby 569 | use_frameworks! 570 | pod 'KeychainAccess' 571 | ``` 572 | 573 | ### Carthage 574 | 575 | KeychainAccess is available through [Carthage](https://github.com/Carthage/Carthage). To install 576 | it, simply add the following line to your Cartfile: 577 | 578 | `github "kishikawakatsumi/KeychainAccess"` 579 | 580 | ### Swift Package Manager 581 | 582 | KeychainAccess is also available through [Swift Package Manager](https://github.com/apple/swift-package-manager/). 583 | 584 | #### Xcode 585 | 586 | Select `File > Add Packages... > Add Package Dependency...`, 587 | 588 | 589 | 590 | #### CLI 591 | 592 | First, create `Package.swift` that its package declaration includes: 593 | 594 | ```swift 595 | // swift-tools-version:5.0 596 | import PackageDescription 597 | 598 | let package = Package( 599 | name: "MyLibrary", 600 | products: [ 601 | .library(name: "MyLibrary", targets: ["MyLibrary"]), 602 | ], 603 | dependencies: [ 604 | .package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "3.0.0"), 605 | ], 606 | targets: [ 607 | .target(name: "MyLibrary", dependencies: ["KeychainAccess"]), 608 | ] 609 | ) 610 | ``` 611 | 612 | Then, type 613 | 614 | ```shell 615 | $ swift build 616 | ``` 617 | 618 | ### To manually add to your project 619 | 620 | 1. Add `Lib/KeychainAccess.xcodeproj` to your project 621 | 2. Link `KeychainAccess.framework` with your target 622 | 3. Add `Copy Files Build Phase` to include the framework to your application bundle 623 | 624 | _See [iOS Example Project](https://github.com/kishikawakatsumi/KeychainAccess/tree/master/Examples/Example-iOS) as reference._ 625 | 626 | 627 | 628 | ## Author 629 | 630 | kishikawa katsumi, kishikawakatsumi@mac.com 631 | 632 | ## License 633 | 634 | KeychainAccess is available under the MIT license. See the LICENSE file for more info. 635 | -------------------------------------------------------------------------------- /Sources/Keychain.swift: -------------------------------------------------------------------------------- 1 | ../Lib/KeychainAccess/Keychain.swift --------------------------------------------------------------------------------