Finish first version of Project 28

This commit is contained in:
CypherPoet 2019-02-15 07:39:14 -05:00
parent 8f4c54563f
commit b1f841105b
63 changed files with 11233 additions and 22 deletions

View File

@ -0,0 +1 @@
github "kishikawakatsumi/KeychainAccess"

View File

@ -0,0 +1 @@
github "kishikawakatsumi/KeychainAccess" "v3.1.2"

View File

@ -0,0 +1,28 @@
# OS X
.DS_Store
# Xcode
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
profile
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Bundler
.bundle
vendor/
# Carthage
Carthage/Build

View File

@ -0,0 +1,98 @@
language: objective-c
cache:
directories:
- Lib/vendor
install:
- "(cd Lib && bundle install --path=vendor/bundle --binstubs=vendor/bin)"
before_script:
- ./Lib/Scripts/decode_cert.sh || true
- ./Lib/Scripts/add_key.sh || true
script:
- "(cd Lib && travis_retry bundle exec rake $ACTION)"
matrix:
include:
- osx_image: xcode10
env: ACTION=build
- osx_image: xcode10
env: ACTION='build:carthage'
- osx_image: xcode10
env: ACTION='test:iphonesimulator'
- osx_image: xcode10
env: ACTION='test:appletvsimulator'
- osx_image: xcode10
env: ACTION='test:macosx'
- osx_image: xcode9.4
env: ACTION=build
- osx_image: xcode9.4
env: ACTION='build:carthage'
- osx_image: xcode9.4
env: ACTION='test:iphonesimulator'
- osx_image: xcode9.4
env: ACTION='test:appletvsimulator'
- osx_image: xcode9.4
env: ACTION='test:macosx'
- osx_image: xcode9.3
env: ACTION=build
- osx_image: xcode9.3
env: ACTION='build:carthage'
- osx_image: xcode9.3
env: ACTION='test:iphonesimulator'
- osx_image: xcode9.3
env: ACTION='test:appletvsimulator'
- osx_image: xcode9.3
env: ACTION='test:macosx'
- osx_image: xcode9.2
env: ACTION=build
- osx_image: xcode9.2
env: ACTION='build:carthage'
- osx_image: xcode9.2
env: ACTION='test:iphonesimulator'
- osx_image: xcode9.2
env: ACTION='test:appletvsimulator'
- osx_image: xcode9.2
env: ACTION='test:macosx'
- osx_image: xcode9.1
env: ACTION=build
- osx_image: xcode9.1
env: ACTION='build:carthage'
- osx_image: xcode9.1
env: ACTION='test:iphonesimulator'
- osx_image: xcode9.1
env: ACTION='test:appletvsimulator'
- osx_image: xcode9.1
env: ACTION='test:macosx'
- osx_image: xcode9
env: ACTION=build
- osx_image: xcode9
env: ACTION='build:carthage'
- osx_image: xcode9
env: ACTION='test:iphonesimulator'
- osx_image: xcode9
env: ACTION='test:appletvsimulator'
- osx_image: xcode9
env: ACTION='test:macosx'
- osx_image: xcode8.3
env: ACTION=build
- osx_image: xcode8.3
env: ACTION='build:carthage'
- osx_image: xcode8.3
env: ACTION='test:iphonesimulator'
- osx_image: xcode8.3
env: ACTION='test:appletvsimulator'
- osx_image: xcode8.3
env: ACTION='test:macosx'
env:
global:
- LANG=en_US.UTF-8
- LC_ALL=en_US.UTF-8
- secure: KL59HA2XSRa215qVXXnFpx48Tb/k+vNfFAbzyc+0M4mXl1VhSJv3bkTslqDrX822t3iFDFYhXbJ6aUo7szSdcbnCXU7VIhNPRK5QM00eS1AI4V0UwDQZ06g2f4Dmt+cQxACg+0CB0OaPnUCA4rkQQKeBMAWa67Tp2hNgQHwsnio=
- secure: B8zXiyX1zEq6uWaCxap5iW1joQBoOjNjSUlcs1t+QKdaFCFtjOI8C1JCClzk7rTnGNDDrhahFlE8yskSNKoBsaW2UJ8TzPIkD4F2pkxTHkaFQl/GBsdbHdOUFL4h0/zGQ6wY1Qhw7C+8+3U+1c9QbnNw6jOQwXTF6gs/XTNzG9Y=
branches:
only:
- master

View File

@ -0,0 +1,419 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
14DAEE961A51E1BE0070B77E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEE951A51E1BE0070B77E /* AppDelegate.swift */; };
14DAEE9B1A51E1BE0070B77E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE991A51E1BE0070B77E /* Main.storyboard */; };
14DAEE9D1A51E1BE0070B77E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE9C1A51E1BE0070B77E /* Images.xcassets */; };
14DAEEA01A51E1BE0070B77E /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */; };
14DAEEB71A51E2690070B77E /* AccountsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEEB51A51E2690070B77E /* AccountsViewController.swift */; };
14DAEEB81A51E2690070B77E /* InputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14DAEEB61A51E2690070B77E /* InputViewController.swift */; };
14DAEEC91A51E2D00070B77E /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */; };
14DAEECB1A51E2E10070B77E /* KeychainAccess.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
1470425D1D6FFA97005A4C6E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 14A630151D3293C700809B3F;
remoteInfo = TestHost;
};
14DAEEC01A51E2A60070B77E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 140F195C1A49D79400B0016A;
remoteInfo = "KeychainAccess-iOS";
};
14DAEEC21A51E2A60070B77E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 140F19671A49D79500B0016A;
remoteInfo = "KeychainAccess-iOSTests";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
14DAEECA1A51E2D70070B77E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
14DAEECB1A51E2E10070B77E /* KeychainAccess.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
145652E11D898BB9006E8D0E /* Example-iOS.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Example-iOS.entitlements"; sourceTree = "<group>"; };
14DAEE901A51E1BE0070B77E /* Example-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
14DAEE941A51E1BE0070B77E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
14DAEE951A51E1BE0070B77E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
14DAEE9A1A51E1BE0070B77E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
14DAEE9C1A51E1BE0070B77E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
14DAEE9F1A51E1BE0070B77E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
14DAEEB51A51E2690070B77E /* AccountsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsViewController.swift; sourceTree = "<group>"; };
14DAEEB61A51E2690070B77E /* InputViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputViewController.swift; sourceTree = "<group>"; };
14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KeychainAccess.xcodeproj; path = ../../Lib/KeychainAccess.xcodeproj; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
14DAEE8D1A51E1BE0070B77E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14DAEEC91A51E2D00070B77E /* KeychainAccess.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
14DAEE871A51E1BE0070B77E = {
isa = PBXGroup;
children = (
14DAEE921A51E1BE0070B77E /* Example-iOS */,
14DAEE911A51E1BE0070B77E /* Products */,
14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */,
);
sourceTree = "<group>";
};
14DAEE911A51E1BE0070B77E /* Products */ = {
isa = PBXGroup;
children = (
14DAEE901A51E1BE0070B77E /* Example-iOS.app */,
);
name = Products;
sourceTree = "<group>";
};
14DAEE921A51E1BE0070B77E /* Example-iOS */ = {
isa = PBXGroup;
children = (
14DAEE951A51E1BE0070B77E /* AppDelegate.swift */,
14DAEEB51A51E2690070B77E /* AccountsViewController.swift */,
14DAEEB61A51E2690070B77E /* InputViewController.swift */,
14DAEE991A51E1BE0070B77E /* Main.storyboard */,
14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */,
14DAEE9C1A51E1BE0070B77E /* Images.xcassets */,
14DAEE931A51E1BE0070B77E /* Supporting Files */,
);
path = "Example-iOS";
sourceTree = "<group>";
};
14DAEE931A51E1BE0070B77E /* Supporting Files */ = {
isa = PBXGroup;
children = (
14DAEE941A51E1BE0070B77E /* Info.plist */,
145652E11D898BB9006E8D0E /* Example-iOS.entitlements */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
14DAEEBA1A51E2A60070B77E /* Products */ = {
isa = PBXGroup;
children = (
14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */,
14DAEEC31A51E2A60070B77E /* KeychainAccessTests.xctest */,
1470425E1D6FFA97005A4C6E /* TestHost.app */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
14DAEE8F1A51E1BE0070B77E /* Example-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14DAEEAF1A51E1BE0070B77E /* Build configuration list for PBXNativeTarget "Example-iOS" */;
buildPhases = (
14DAEE8C1A51E1BE0070B77E /* Sources */,
14DAEE8D1A51E1BE0070B77E /* Frameworks */,
14DAEE8E1A51E1BE0070B77E /* Resources */,
14DAEECA1A51E2D70070B77E /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "Example-iOS";
productName = "Example-iOS";
productReference = 14DAEE901A51E1BE0070B77E /* Example-iOS.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
14DAEE881A51E1BE0070B77E /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "kishikawa katsumi";
TargetAttributes = {
14DAEE8F1A51E1BE0070B77E = {
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 1000;
};
};
};
buildConfigurationList = 14DAEE8B1A51E1BE0070B77E /* Build configuration list for PBXProject "Example-iOS" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 14DAEE871A51E1BE0070B77E;
productRefGroup = 14DAEE911A51E1BE0070B77E /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 14DAEEBA1A51E2A60070B77E /* Products */;
ProjectRef = 14DAEEB91A51E2A60070B77E /* KeychainAccess.xcodeproj */;
},
);
projectRoot = "";
targets = (
14DAEE8F1A51E1BE0070B77E /* Example-iOS */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
1470425E1D6FFA97005A4C6E /* TestHost.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = TestHost.app;
remoteRef = 1470425D1D6FFA97005A4C6E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
14DAEEC11A51E2A60070B77E /* KeychainAccess.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = KeychainAccess.framework;
remoteRef = 14DAEEC01A51E2A60070B77E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
14DAEEC31A51E2A60070B77E /* KeychainAccessTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = KeychainAccessTests.xctest;
remoteRef = 14DAEEC21A51E2A60070B77E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
14DAEE8E1A51E1BE0070B77E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14DAEE9B1A51E1BE0070B77E /* Main.storyboard in Resources */,
14DAEEA01A51E1BE0070B77E /* LaunchScreen.xib in Resources */,
14DAEE9D1A51E1BE0070B77E /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
14DAEE8C1A51E1BE0070B77E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14DAEEB81A51E2690070B77E /* InputViewController.swift in Sources */,
14DAEEB71A51E2690070B77E /* AccountsViewController.swift in Sources */,
14DAEE961A51E1BE0070B77E /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
14DAEE991A51E1BE0070B77E /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
14DAEE9A1A51E1BE0070B77E /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
14DAEE9E1A51E1BE0070B77E /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
14DAEE9F1A51E1BE0070B77E /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
14DAEEAD1A51E1BE0070B77E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "Example-iOS/Example-iOS.entitlements";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.1;
};
name = Debug;
};
14DAEEAE1A51E1BE0070B77E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "Example-iOS/Example-iOS.entitlements";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.1;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
14DAEEB01A51E1BE0070B77E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "Example-iOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
};
name = Debug;
};
14DAEEB11A51E1BE0070B77E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 27AEDK3C9F;
INFOPLIST_FILE = "Example-iOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
14DAEE8B1A51E1BE0070B77E /* Build configuration list for PBXProject "Example-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14DAEEAD1A51E1BE0070B77E /* Debug */,
14DAEEAE1A51E1BE0070B77E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
14DAEEAF1A51E1BE0070B77E /* Build configuration list for PBXNativeTarget "Example-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14DAEEB01A51E1BE0070B77E /* Debug */,
14DAEEB11A51E1BE0070B77E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 14DAEE881A51E1BE0070B77E /* Project object */;
}

View File

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14DAEE8F1A51E1BE0070B77E"
BuildableName = "Example-iOS.app"
BlueprintName = "Example-iOS"
ReferencedContainer = "container:Example-iOS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14DAEEA41A51E1BE0070B77E"
BuildableName = "Example-iOSTests.xctest"
BlueprintName = "Example-iOSTests"
ReferencedContainer = "container:Example-iOS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14DAEEA41A51E1BE0070B77E"
BuildableName = "Example-iOSTests.xctest"
BlueprintName = "Example-iOSTests"
ReferencedContainer = "container:Example-iOS.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14DAEE8F1A51E1BE0070B77E"
BuildableName = "Example-iOS.app"
BlueprintName = "Example-iOS"
ReferencedContainer = "container:Example-iOS.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14DAEE8F1A51E1BE0070B77E"
BuildableName = "Example-iOS.app"
BlueprintName = "Example-iOS"
ReferencedContainer = "container:Example-iOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14DAEE8F1A51E1BE0070B77E"
BuildableName = "Example-iOS.app"
BlueprintName = "Example-iOS"
ReferencedContainer = "container:Example-iOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,149 @@
//
// AccountsViewController.swift
// Example
//
// Created by kishikawa katsumi on 2014/12/25.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
import KeychainAccess
class AccountsViewController: UITableViewController {
var itemsGroupedByService: [String: [[String: Any]]]?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadData()
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK:
override func numberOfSections(in tableView: UITableView) -> Int {
if itemsGroupedByService != nil {
let services = Array(itemsGroupedByService!.keys)
return services.count
}
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let services = Array(itemsGroupedByService!.keys)
let service = services[section]
let items = Keychain(service: service).allItems()
return items.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let services = Array(itemsGroupedByService!.keys)
return services[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let services = Array(itemsGroupedByService!.keys)
let service = services[indexPath.section]
let items = Keychain(service: service).allItems()
let item = items[indexPath.row]
cell.textLabel?.text = item["key"] as? String
cell.detailTextLabel?.text = item["value"] as? String
return cell
}
#if swift(>=4.2)
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let services = Array(itemsGroupedByService!.keys)
let service = services[indexPath.section]
let keychain = Keychain(service: service)
let items = keychain.allItems()
let item = items[indexPath.row]
let key = item["key"] as! String
keychain[key] = nil
if items.count == 1 {
reloadData()
tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic)
} else {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
#else
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let services = Array(itemsGroupedByService!.keys)
let service = services[indexPath.section]
let keychain = Keychain(service: service)
let items = keychain.allItems()
let item = items[indexPath.row]
let key = item["key"] as! String
keychain[key] = nil
if items.count == 1 {
reloadData()
tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic)
} else {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
#endif
// MARK:
func reloadData() {
let items = Keychain.allItems(.genericPassword)
itemsGroupedByService = groupBy(items) { item -> String in
if let service = item["service"] as? String {
return service
}
return ""
}
}
}
private func groupBy<C: Collection, K: Hashable>(_ xs: C, key: (C.Iterator.Element) -> K) -> [K:[C.Iterator.Element]] {
var gs: [K:[C.Iterator.Element]] = [:]
for x in xs {
let k = key(x)
var ys = gs[k] ?? []
ys.append(x)
gs.updateValue(ys, forKey: k)
}
return gs
}

View File

@ -0,0 +1,41 @@
//
// AppDelegate.swift
// Example
//
// Created by kishikawa katsumi on 2014/12/25.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
#if swift(>=4.2)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#else
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#endif
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11198.2" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View File

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11198.2" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Vxu-PH-fkp">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Keychain Access-->
<scene sceneID="P0Q-z6-lcc">
<objects>
<tableViewController id="Jtp-Af-YIM" customClass="AccountsViewController" customModule="Example_iOS" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="3Yx-it-Kem">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" textLabel="6jg-UI-oEw" detailTextLabel="1ym-9d-Zvi" style="IBUITableViewCellStyleValue1" id="t8g-pm-LZL">
<rect key="frame" x="0.0" y="119.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="t8g-pm-LZL" id="LZV-Cj-dTd">
<frame key="frameInset" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6jg-UI-oEw">
<frame key="frameInset" minX="15" minY="12" width="31.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="1ym-9d-Zvi">
<frame key="frameInset" minX="318.5" minY="12" width="41.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="Jtp-Af-YIM" id="4M4-v1-LUg"/>
<outlet property="delegate" destination="Jtp-Af-YIM" id="A0G-ls-f5i"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Keychain Access" id="ETS-AE-f13">
<barButtonItem key="rightBarButtonItem" systemItem="add" id="Vlq-2u-IZC">
<connections>
<segue destination="UPc-C5-mNA" kind="presentation" id="M5v-yk-38B"/>
</connections>
</barButtonItem>
</navigationItem>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0Wm-gm-SBT" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="231" y="164"/>
</scene>
<!--Input View Controller-->
<scene sceneID="W6S-gz-OFV">
<objects>
<tableViewController id="Ci6-Xb-OHW" customClass="InputViewController" customModule="Example_iOS" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="Nsh-ip-0lp">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<sections>
<tableViewSection id="kcl-lq-NwO">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="7RU-rl-oP2">
<rect key="frame" x="0.0" y="99" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="7RU-rl-oP2" id="1P6-M9-7lh">
<frame key="frameInset" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="zyi-Id-S29">
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
<connections>
<action selector="editingChangedWithSender:" destination="Ci6-Xb-OHW" eventType="editingChanged" id="aKf-aq-f3d"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="zyi-Id-S29" secondAttribute="bottom" constant="8.5" id="8HW-xC-qCD"/>
<constraint firstItem="zyi-Id-S29" firstAttribute="leading" secondItem="1P6-M9-7lh" secondAttribute="leading" constant="15" id="SfW-kJ-QNR"/>
<constraint firstAttribute="trailing" secondItem="zyi-Id-S29" secondAttribute="trailing" constant="8" id="bLO-Bw-sya"/>
<constraint firstItem="zyi-Id-S29" firstAttribute="top" secondItem="1P6-M9-7lh" secondAttribute="top" constant="9" id="kQy-Un-xgj"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WnJ-H0-TUL">
<rect key="frame" x="0.0" y="143" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WnJ-H0-TUL" id="jtU-kW-you">
<frame key="frameInset" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="oDn-kk-0de">
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" secureTextEntry="YES"/>
<connections>
<action selector="editingChangedWithSender:" destination="Ci6-Xb-OHW" eventType="editingChanged" id="OxY-ei-oaj"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="oDn-kk-0de" secondAttribute="bottom" constant="8.5" id="H0O-q7-Oev"/>
<constraint firstItem="oDn-kk-0de" firstAttribute="leading" secondItem="jtU-kW-you" secondAttribute="leading" constant="15" id="ZM8-Hw-sHu"/>
<constraint firstItem="oDn-kk-0de" firstAttribute="top" secondItem="jtU-kW-you" secondAttribute="top" constant="9" id="ZPq-1v-AC0"/>
<constraint firstAttribute="trailing" secondItem="oDn-kk-0de" secondAttribute="trailing" constant="8" id="dQ7-qd-nhJ"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection id="Rub-6X-UyU">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WR8-y3-rgh">
<rect key="frame" x="0.0" y="207" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WR8-y3-rgh" id="607-H8-OGj">
<frame key="frameInset" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Service" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="bQG-QF-hkM">
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
<connections>
<action selector="editingChangedWithSender:" destination="Ci6-Xb-OHW" eventType="editingChanged" id="enS-1b-yrF"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="bQG-QF-hkM" firstAttribute="top" secondItem="607-H8-OGj" secondAttribute="top" constant="9" id="DQ0-kV-Lps"/>
<constraint firstAttribute="bottom" secondItem="bQG-QF-hkM" secondAttribute="bottom" constant="8.5" id="GaT-9h-fEV"/>
<constraint firstAttribute="trailing" secondItem="bQG-QF-hkM" secondAttribute="trailing" constant="8" id="Hyt-ex-iBJ"/>
<constraint firstItem="bQG-QF-hkM" firstAttribute="leading" secondItem="607-H8-OGj" secondAttribute="leading" constant="15" id="P5p-dR-6Av"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="Ci6-Xb-OHW" id="0NJ-cf-dSM"/>
<outlet property="delegate" destination="Ci6-Xb-OHW" id="qnF-hg-qI2"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="3Gf-V3-uxm">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="wFd-wq-9G5">
<connections>
<action selector="cancelActionWithSender:" destination="Ci6-Xb-OHW" id="2eJ-a8-IRd"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" enabled="NO" systemItem="save" id="ueY-jZ-6ms">
<connections>
<action selector="saveActionWithSender:" destination="Ci6-Xb-OHW" id="Oty-ij-QPW"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="cancelButton" destination="wFd-wq-9G5" id="n1X-zW-EDm"/>
<outlet property="passwordField" destination="oDn-kk-0de" id="QgI-b3-qHF"/>
<outlet property="saveButton" destination="ueY-jZ-6ms" id="dzq-xg-N4m"/>
<outlet property="serviceField" destination="bQG-QF-hkM" id="mjQ-AK-Z4Z"/>
<outlet property="usernameField" destination="zyi-Id-S29" id="Ws1-i5-KzY"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="t3l-SW-jHz" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="231" y="897"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="Oh4-Vx-wYM">
<objects>
<navigationController id="UPc-C5-mNA" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Qkz-Dp-KoE">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="Ci6-Xb-OHW" kind="relationship" relationship="rootViewController" id="JRp-AT-sQa"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="XeL-mf-rFl" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-589" y="897"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="k0A-AE-7fY">
<objects>
<navigationController id="Vxu-PH-fkp" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="NWb-ht-ElO">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="Jtp-Af-YIM" kind="relationship" relationship="rootViewController" id="1GL-67-9eh"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dsG-PT-AyH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-589" y="164"/>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.kishikawakatsumi.Example-iOS</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,53 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,80 @@
//
// InputViewController.swift
// Example
//
// Created by kishikawa katsumi on 2014/12/26.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
import KeychainAccess
class InputViewController: UITableViewController {
@IBOutlet weak var saveButton: UIBarButtonItem!
@IBOutlet weak var cancelButton: UIBarButtonItem!
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
@IBOutlet weak var serviceField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 44.0
tableView.estimatedRowHeight = 44.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK:
@IBAction func cancelAction(sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
@IBAction func saveAction(sender: UIBarButtonItem) {
let keychain: Keychain
if let service = serviceField.text, !service.isEmpty {
keychain = Keychain(service: service)
} else {
keychain = Keychain()
}
keychain[usernameField.text!] = passwordField.text
dismiss(animated: true, completion: nil)
}
@IBAction func editingChanged(sender: UITextField) {
switch (usernameField.text, passwordField.text) {
case let (username?, password?):
saveButton.isEnabled = !username.isEmpty && !password.isEmpty
case (_?, nil):
saveButton.isEnabled = false
case (nil, _?):
saveButton.isEnabled = false
case (nil, nil):
saveButton.isEnabled = false
}
}
}

View File

@ -0,0 +1,35 @@
Pod::Spec.new do |s|
s.name = 'KeychainAccess'
s.version = '3.1.1'
s.summary = 'KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X.'
s.description = <<-DESC
KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X.
Makes using Keychain APIs exremely easy and much more palatable to use in Swift.
Features
- Simple interface
- Support access group
- Support accessibility
- Support iCloud sharing
- **Support TouchID and Keychain integration (iOS 8+)**
- **Support Shared Web Credentials (iOS 8+)**
- Works on both iOS & OS X
- watchOS and tvOS are also supported
DESC
s.homepage = 'https://github.com/kishikawakatsumi/KeychainAccess'
s.screenshots = 'https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/01.png'
s.license = 'MIT'
s.author = { 'kishikawa katsumi' => 'kishikawakatsumi@mac.com' }
s.source = { :git => 'https://github.com/kishikawakatsumi/KeychainAccess.git', :tag => "v#{s.version}" }
s.social_media_url = 'https://twitter.com/k_katsumi'
s.requires_arc = true
s.source_files = 'Lib/KeychainAccess/*.swift'
s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.1' }
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.9'
s.watchos.deployment_target = '2.0'
s.tvos.deployment_target = '9.0'
end

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Lib/KeychainAccess.xcodeproj">
</FileRef>
<FileRef
location = "group:Examples/Example-iOS/Example-iOS.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 kishikawa katsumi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,158 @@
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
m1nn1kcLs46WQmS7a7XSHQ==

View File

@ -0,0 +1,67 @@
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

View File

@ -0,0 +1,188 @@
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

View File

@ -0,0 +1,131 @@
U2FsdGVkX1/A9JqBXQY1nHIgQ22pp/7/eETLbgBOMJgqmSZP79CPn1brO+WrYJe4
4UcW1ZYnJYyIz+tINiie2XGQqLExiFh9cgI/aJRvKt4Aq0B7VZ/wk1bVdvmbjojX
U6zradMwdAhTPEzDz1lRhAcvIJgTLxDTCiJWxPakAEuDSbjUHhAqANmCKoPtOLlE
zP04L6orkUn3ZFUvanr1UcTy47FOYCrOqFSkHr11RNN+akIN8pZrH6FJNRQYYMc+
SNyswtwMT/m0GBPk7vN5qzuqhtrW8hpxFlAf/OWZK2zD88myR36K7eonZHddgTe8
JHxPTbhx09P8FdqB5ZRnhAIeidSBvVosfs58G7Mdm1XVP71HTy43qC0IBaGbLJkN
h2ngsZDHVLapX3Si0faHDxaM0OVHs7sD2r/eiB1mzXmV07WiT8AVPgskZkMgW0eI
R+t0JnDkicR26IGQSJ5+rDwcwUIoSNZVB7EqcYOOT0HpDhUbEDM6C0iTGLEA237g
ECc71XVkIf7dxudnn8k0eDGw2+OHv+opi54MSks1KImo4HiWCeHT46RVyNemVCwT
1iijESZv1PmKAbg8yLwQDLXKDIJyIHIuILiAsCsG1yNkCb6lE4wGKVSMpxMhE1hL
eW9dTLcl1tr/9JAIJFP1MYSZVy6JIBbz9IKGRO4ZmTimRCR8cyGSQNa0btg7hzkY
C+4fFeUA/ZkkTeufIy/v7V9u6vsMuWU4hsdQTXzgrnougxLOVGQpbmf58nV/YHhl
6JZ4n1EQnLFxFP/a1kEBfA6keG2dRjTSvm/HIemFI57KozuQonE7T4RXNY2vvjyh
HrEjR7pI1JJe5SXRwPqCKuF/ZyqamQ70XfmiLNmNAS4GgeWYG2mCQcj7/lcJ5bUK
tjMSC85vCGbTl0Bt7NGl6yDXzciRUeOX4q86SGTlrWmgk5y4+Z2DjDgscGblJYU4
9QoDSNiqVvrF1NnSc9VwHCjytfXaB9+76yDCgkSBRbUhbykHZIzbOfNQ6R7EQlKP
RZOr7Z5BqMqw//yF/wBEv1PMa0fhCvvyzrLmKGzfqljswNZtoLpHHjFvCVjSPdQD
HcmWWPxDA6nfpP3c01pEZdAQYKE3tfpgqXjymS08x2MXwRLL5MCZerXGEOgtjB8G
ui31XiapDlEa6YCjVpO8567sEzBrsBeIadQGDA/LOE9xHrm4dHsL3TERclLp75nS
8Tc7WY+rmePN8hXCODEsf5CV0z5VQJdX7hYhrAilEkjU0vwObdvObVgWz+Ti5Gvm
T9LU7pLc0TkaqI+lcwMQ3VG8Dp3BZSxxHyihy53Ug6JS/gofkRgHxG3rB13z/nby
avswN81lLXvoAGTb0iVuLkVaKgxamNujLUVbXV+IhiyhqpqOXI2X9HYIMwi4Gjvp
Q2Z/djJFoxXOiqSGVpngKa65eDATJ9OpurKrBcJ+s35KdXiiIzEbH8C5Z4Cdx1KB
mpzJW/6KzZzNLe+h9NE82j2CNPFqT24Nq1k2tPXPtq1UX0E1RKFI9txxj6FREkg4
LtIvflqiBt7mX5eROpHqqrvKDr87/P84rGoDaV1SZMYKRqCeq8FOtTnS9hIKqxJ9
zkchIlCaM8S1Hkc1J+F/6ZXHet7rUE7fnO1FjXdEUWyUbsJPpVl6rTHkZaOtvfiD
kXvkm7PoWX7NeLGDLFHa1Si6GPsYR2ww48jnKHpRuRp6llbcQ7TJz0ZSr2MdY5kv
TxQm5XeONaBvn5cNBFHQ275K50/jO1M+IC6LL7IUBjvbdoBlLdBd09YQT5CDg3Qr
kIQxqFFQDmDslDnl7OlwimM+A10PN2z0tBtNZud1n/ZbbL5H5eoZSkrRgrMDvzVV
JAuJ6diyegT75ZKCi+vR37kpb0hx1gP3EkDyuuja+BaMBhSz7GqOmWsHuetSeVE/
GPzrI8dKN+xrUerPniAiqmzbn7YfCiog+PMVgdacy02RdIYUL7jB6qQAvJhAB85b
sfWPhgL2O1UiuS4WxtTtaStgsoai6jApBElkoCMDQJLIHaARMHjhpih2nffqGrm5
dsu7RliE++6YFw3c6+saUaRuT65+FqL8S/NNxd3Mqq09UY8FhotVaTY1IcTCGx6y
m25gJVSRssfus4YA6ySphabzwrUsfz12PoMvYEZvYSapHuhk3YlMZaXHS/QMfFy3
7qiZ7+yWH+4+jicY9GsCuqm6jFUpEKK3B8ljlNqQCGltPt8FEWf6iv4XCuPc9EOS
wQHWuRntuH2k8b9ikslk2rkBN4TG6SOcgVqGaz6cInKyPiWocrAzUnUBLeH4j+iz
EOiFdz6xCqyQu0qK1NgeuBfw604dJtRMJSlv7RuPuJXLqcDzJG27YY7O1IUpM020
P+gGG+49Tcm0Xjcg193E5A7BxMMo963WUjfnk9QetS61+7/QYOyxrOYv+D/WxC/Z
0ej/diD836XsaZ5rczSL3kVMYcoiypeteBS9mFJQmLydJVKtPfZDYfoJDX7QvZ6o
CArXjdZ/yM8SZ1g7AfqGyiCoSM+qqo2b1Kqnw6pnveL8lxHjLuUlOifqUUslw2ON
30XmRo7wbAos1cKKQRcHaxiwx/PrVvuL1wQ2bJ5Jcp/RN1lJeMiV9VmzcloIJINN
8n3K9gNlIK85wR/XyXpkRD+xfqJwyTKEadQ0IN0iFG1WwybVj2ydXJehgKCJymjI
bZQy/8/DNgXIIXhOZpgDwdwe1rXI9VIRBXutwICcCxC/dwIModHF9TDr0h2UpoAH
NA0wiTgCJsGNQdg0wQHGMhC07qvG59gDZ/QL5DZ/IZr1GChku51OkX/I+hLLeiIk
qXlcbGfAF+tKVaJrCr1L4cvMfD/tfOKjkDJq+7BW7+gNM2LuNdRyY/J/8bLU8y99
/lEcY4uTg1ZIfJEyT3c4gG5OSrqKEYtOxAMmYEsv6FYsmDCfVfu0HvCXXb3rrNSR
9yKDs9jdQe/8IuEOq4X8jrR/4gSxE4VctCF+6WPg8UuM+ncveE3+bgG6Dw4H8/yK
9p5YUB3kAHHbV6+68qPnDiS9oEYowiWfYZEUvc4vZzif/BXHbmJ0zs9U20O8UfBs
ZhevvTIUQyZC/gAs6nD5TnPfZATtmV1FPFHabi5UVMhmbyvCKZu4MC2ybYDj651/
yrAqXehphsqD0aBSijqtEhLPtvF4BDC5HxU4y2fWIR3Waum/ZHy5biRWsoei5Qr9
1uqX/zAoFGXC8UswmOE9hy1LhtIBz9vI7R7QgzZEKm+D1MHrcQMnFRo56LZsBOLA
5hGzX3nU3hWjKWyEt/G+ISpSIxx5LnWE2HkEqNAhbo8ag+yonLhE5JT5EczLBuRd
OZyxUriETWmSSxU36ymxwnt2L1Wo5n5XiaKUsBV6JCdt2KS9n3AQFjFX7Qutctop
SiLdk9aniXGVQxmpt7gtxEgXyab//DVfgvk/4cVl89hlrYVxSj2Eaw3glcidnsmP
rJUtUqMMAEu+Z6OfH98kMZQEmCsDvTWEKu6bu+U3UNGqsR/Ckxv6LyCUypDFXa+u
g9s3r3pTQDHjRqUnHWJbEyzjOuHs9s1jH+kOGHbkz3o23ivc89dvkSUJHjiYzE8I
g38NRfs6VfLqPtDGRm68WUsRd0w9dssS3iuIztNAV3zNnRN6EGEL//imrvwMC4Hj
ZyXgHLdEmlbkLknAQfb1dhXj1kdH0BOhu+OJ9RZdkq4YEmQw94Ga5gcJUT/B0JM0
3+E05Y+FPDzTOikFVaR0AQP1ZvdVVoqLcfzAlYmJzw3tWq81HExdoyxwZuANPyyE
JbILwU9sETfdm/OoL5w7DL11fS8OogLw4Nrr3sEIEuT+IjMd+nnSqDOTzPoInOjM
FmuNVHoaT71rmHzFbJu+Ej6d2NdmO4SEehu+0J4pVNYRBrsY8DtSfeJ+webyiipF
7DnVcCtne/OubjkucB1lwwQN3j5EWaGJuK7+/5nOeo98tj9NWMXkjapQJp3RDlXl
x2q2+6O8uYBAAVgiBUwOBg77ID48Q9W8cml7FViv+RPXiPoEbkqFHIO0I4h4cfdV
oGUzQysWJIpXt4B+0bKDDgxaiqHI5rBVJOXEYzTFhZ1Ipa90vpgf6RESLsPGvoUJ
1fytDK1ClE67cw0ft3fZrNPvYsFrbNy6pT6j5o76TxKPBsCmll+M4bnizXyv26Ac
Dz0gUN8ynXcUT/22CepTreJmvdOyps/EucbKYtMpPp9EMBZqLGd0OfDkuFIywHRF
SUg5bE0UllyICI8/17MdCKDda5dzXdi3OeEwKQrdQUxp1Kzsbd7wBDqecVU60v2S
kXZIucNjwiWu8CGSOOdmBQMQlTJZ/uk6UpqI+npSrckHWgSGjdJcOrtaLiBKeasR
D6Td0LohKPzlI/bDhUD9YvaCaqEpTb+FQo9OapdH46eB8olJiZpoc38vyGLFuDnv
AHC32vTV5r3ZB0lmgahT82mfoL6M9kOIHjgZKZxX56fjZCh0S7ahPsSBMUC5YtAn
rKaIbSPYlBEg7sbGvxcWPnRAgKfUww2kWXXH/UbtGRguL51T0EaBSDzyB1M/qYpg
4sqI8Cbr8RiTH7RrV0Fp56P7UzrsiVs115IdpGcZaaciu1IwKMx6w6E1sbZaKytc
iVCzVUl0UGUYmC5atrMBEf68Z74BFBDyl73fru5WafGxTXMBL10YMvDPbyDmjaKG
2logR0ZbUtKztJuA00SJ7EaYn25RaiHzTTqT2CPGf7w1wobbxrEb0MDKSj+0srRq
nPsdhLpbn2YF2lDqwNEfUsQY33B/FAoOaBaRMFXtIOWEEFp1Nw/EIW6/WK2vJJXV
HoN/WrNNCCwWGxcJnzwwZjVaXUF6G/fo/TV7Q3VzVj9QE5s2DG3gUuGC1JROTqUw
vgjf/owUNuxfOXXbO8GpFkyfG9qWuDSY9HcDOVvakUlP9BfSHWO6QsvomrQyZx8Q
SVx4a92SCC4mNK3s2kzvN1bd2CJFguk7YaXFaivyqgpjMLHMBueRV0hA5YYrgoAu
S5LaQ0htOjaCgQqD35cOr7GigerBJFc6yQ5FAmPg2VDleld1iLOr1D7bDwlN5cdK
EIz3YM0bi8qYjkKqqDzy8MDb+7i18OKM21o+Mh7kxNl7tU+ULz8pCK4glD3AzGJv
FJqiwVN0tmFHAXazOJwDYxyM5LHlSLcrWyyG7aE7281cZHHMfJe5bUwMNZd0bDtP
BdNY/xv6g8QW2nJt7ER3pR04P1xDy0leC86ZQ9tUQPaU//Sf9PdYHniAVvNiTS8H
5ol+FchTmfsfbnz5ck16jOVfIc8U+KOUShmCmgQ2oXPeVBRX0+mH39h9PSqDC+ny
UaOj9gntyBWpEncmANw2jheuc0J+Z+vBHRJsENtWRZ/vVufoGIuJrpSWMHyPtZke
pxLmVl/hiI4douKJdHfg1SUQF5l9+o2wXs3RjQm5Aq+r5W58tINn6FortqKV1yHq
44Z+42Vd1uUkJLUY+TufNmrp3xl9aT1rx3zKD75zoxOcRw4OQvYGoaoobyg4M5K5
KN5j0vXyNp4KSGX+33L9macArpgWfM1S6A2iqenUoZjzSpm+7mwVM+9ABua19NRe
1x/LTZDyC8M3aCDfi73Et0mHL7onFr+uAIdWk8bsAuPh6OcfXxDO1iBgHHyNu+XW
OUnXn60MCxUvpjaOy7YiqJu+/RY1AyfAc0thqe9zrexJC/SIgAM7AjKnMkw0qASI
biQllknlrpnIJ3HFgDuNcKZqtGbseLfXRFoSganE2dN4tE+olpFH4OlAC61IMleb
N4rznupMQHOPpX3+BQ56R3yVPZpIG4LJZLn4fw3+6b/LhKbU7hhf3CQnwbK4LDjR
p2G23H0KAP6jDUMZoi3+zF08q5HAdfyxhz2KgK/yUqf8yXAA+3e6fPbo6pzM+9gR
3u/CZzBajx12Okn12/8cIVWy7j9zglsj11XmNgfffRXbF7iQHxKqYdDwk3Qlljaa
TXeg4R+ricLE5EcSugD9g/Bhs6m86hnPvzm/YH4SXf5cmaMDbyLe3ra/KmU+Mtbo
BSF1FGQ3GQUaSsm6VMx8tq4ODW/v6phhEt/kKeYvIPm3NbZcF1LwPEwd9B8PqZIn
joOHunjFkv+AVWo0GOJYY7xXmHuot/GA7WirqgyM6rnsJR0p5R/1xlBaTpAbh9Tl
BFTNnh/NdF62G76AUHI1DLJjcj036tfq4LQmLjw2/YMOsBWBOYrQP/UljwqXzONV
vzjKe1/ks77bFKfGLzerVu0TofmGtzJUn7uD7MCtmSTUaqu9Mx98WDIT7I1nHeZb
/CyPNZt40VN1ZPs7hDzjapHqJrmAPFcVi2NgSTRlwH+8XN4fiyXYwigvilsZtIcv
T93QTNKwJU0Dk2I6fhakcC/pgqkio3nVBDjZrw3UgTETUrJFx9hMUDUPVY3VhW7l
bDWoAaUZeRruJgtN+CfUewma1t41q9Bi1hLHn0XUhPM7Tyjhkoy3nqpODKvMVZwf
5+qK9IzpjqzhWkqdwql3BykAzPtJUpQ3NoizESH8i7vj6PIfSHV748YvP3GgqnD/
9Z6OMShRhD5wtwsFGC5NoQrsfNyLdJTIcDm2+hecJ6Ddpnw/GZp4P5f1DYCpmqDd
hGFKxPU7bhMjmvdyB8qtamirnPtEbcU0LhSmFRLUY71f6YQanSWLlYGt8qZ3Q1KQ
6GGURZANCp7quttPTZcCDs9AWRHtBjehHvCk4mLIosMzGVPCW1ofVuupMsOENEW7
iujRbRuGX8rzkvVkTDkLWBcZmtclHu7iwp49RUHocdKvRCj6DhkNmtr+9GXEGD4T
uX2ErO4tw1e041Z5cZS1z5qDpvH957JkO/sFv1d+EyksiSDhpbBNHuAOJUsQYQ02
BrFDLGIilDCOZ1QtaVOjj6SRqQPF9puy3rF6MTPiaFRGQyrBIYdIub44vI2t+I5F
bGWt4vl6O4NoT9RaI2Ol0hHIPhn+FaEtrsrRc6Fy2XBSw5jhSr7aLvKBly6nOsQ1
pfUTQyNtEoywpJCBFdmlGfmvq7FE3PpX/6fdyewhLn2VChjR2PGUbEeIhM1pXeyV
rqN1M1GsrQqaIAla8A8RGn5qQayTLwSCkvocEIm8YnRsE0lN0jG78sNhNfx2VbSv
pWQcpI0h3g6ZfjkWfesZpO5n1bDvtYpG8QmERKoX/r1AypjjXevoPILDvAuk7vra
vW4VAJ696XepghDYVewE+gs+qBlwOT4b++mkaH5+RS5mGhTDZQwxBEvVyG/sVpS6
+d4uCD8C+3tNIpuvpXcbpr1zV6lZj3wCixCQSHnMZJlcVJETnrNkuFfJ5LMIppL9
Q5181YFXDN0rEIm3WqmP3IJeJhF9Dj7M0rHhlIJk6PvTi5bs72C0tRLCIiQqOcfi
q/ojo6s/3g0rCBRm+/Fz8AxB6wbqxI6x+0Rw703WwTXU/vshqNl3iJljzhno1PWf
2E1z78vYSt5rmAZ+5QAnFzerb/XziYHiQdUfPMY66TpyLIrziZGoW1QEENHT8RwV
lrBdLbPkXcMRFcE6f1jedrWnRAuE6zq/0EgYXUxIk/+nnW/oul6RdbMBxviNAe8U
1gii6ZHoaWoTxROoOQYB0P23Rjf8eJ3r5c2+nZmqsXLDwNeKdlX+uSsS6pLFh7DJ
PWzD44AcMXIjv8Z4uB8pPVbpAbH9oda3GKPZcYQuJ4scScy3USAOYK77T4SY3Y8r
YtTmTD02z3+FDzihUWEoZuWebOSSIgtw6cGMHXrew6oLun9MMeGeUsaJbF9Fm1dA
yGQFHHJU/QRkEsI7UE+jf7st9+gvwoMpW1WNWonO/LWRidMZmtaXxLny/+Rn9jzf
2IYajsbxieXjL3ab196D9HWJZhGUpNNaCD3rIBP/5gmiCb5PZVQTFm7XDN/evb90
ZBAgkKl+5VJoJpQLSOwNQ04D/WMSEkdfK9OmCNY/5ZrOq5YnOodwb0s0aSgpZ9vZ
6TO5Eh5KUekbzOERSYTT7gsHGVzHGcB+cA2ezUTb1MqCM6XPQew09aHJRv30LJML
CH5z2DduTEsiio+pdg8qvgMh+QJTxiTXOH3tEi/TLMgbkasO9R3qWatvkVaX8fqH
pzLUvXNGfwonVgCkQ6S8IaUG4J488A/eUZmF88ATuse2k7vFxiaYtM4qFfcM6Bpc
U594M87s1N/lbShteyE1QRxkhCXrlX/xFo5RXwCqVegQ0Fenjb5Usvf5eKRW4zgE
SDnOmso/z2yXrIJ4sSJdPbrkCiMCq2gd/qe6kGxC53ibGHSQz85kgxXBZFMSIh2/
sM53Di/oIR+zvimoqOIbWKLwBn02oO41sNE0qvsV2C8fy1SVOy6cG8AX6D93PI3f
hfJJH1uvIO2vkPfr+fxvTQ==

View File

@ -0,0 +1,158 @@
U2FsdGVkX19sMm4dCPgcgTnND1wPKUERPjbnGI40mBJnBBi5mimAk6o1qbZ5ciBA
/StXHcQHcZxl+YNP/jcku6q0VI9zxdl7O5pBv2b4dSOlJAg35Jf0BE0C6SlLK9a1
nN1BfFXlA8GKGSRExFOCfBdhE+NcFn7WHNLKkzgwdCCx5BU9+0T997f7DoZ0PANX
YhHLVg0SQmft2q2CuBWdLWJDMoWKYAK/kK0Xr8emcjmTfE66+avfzDRZgpGzXyHs
xkQ1e2+942urkiGqQQy65H6ig2brUPEvNWahEm2ss917+ZK89mgPm1SuQc5m2H0J
FL6llVEgGp20agJRxFNeU2k02EcwVoTCltB43l646M9PRltTtolTh1VnhuLJcJOa
Ns80mfWkqkT+4ibsMZZ4+LJ5bvSMsX/XhZA69qF7vtOaTqGRhO6DdNzLI/cb4Uxu
mwwGN1FrTHzHHiooi6bQ2/Iy+sLMSogBXkxHoTbJJPO0BwzDY1zQsqSYhfojQJRK
sV/ijFYysttTg/W3oCPgnDPUSSUzhR4Po5dUUDeRSat025/dgTgfKxk9dwkakmvQ
ol6ima4OcHSVcghSTpbp3u28v6aDqOzzgMMbP1jK1+m8WFVaQ60YejJAAfSjOgV2
DMp/t0RrzpyiqwX2LTpS6htf1Rqect/DxV0GjMOh0cG6C3NB6WMzlC3CzUPHN9Nt
fYSl76wAbNQn1lLQ4L7xam8QbgFj3ZYLE2/FPt7mpsgxlV/e32l/J8o8OeJ3jEuR
CokbuhWHCqfNRk/i7Y9tyKAskDCb/1XOLjlt2UGyF2Djhw2BkUXjLrp3lHjFDQS3
LfIA/0URYypfZ1uicny9USAdfWjywjgRYZ/mlWZh3jmpgGOba/Is7G/0XeBBh67M
ZzpDWwm8+yqoT0ogISos8GEiAPEZY4No6dYuAJsI898x0bmYFPwpUbmhfrb+b48V
dubveA5BMW1OPiRXngmYoEOWmXcmkzAkU3PofG7Ufqa/F8/rPVJcTNJ5XhQvQOew
WW4DoKtiuvFTUFPXn6qZWx86xir1XS182dfqLldh7VznCnnUctuPHBrt2u7EwIzr
8ZKcvVbuuiXF4ElxsAL4yBWumvZFr9RbHD3OFes/IrIFfP6eGdx1j6wK6mpeoJU5
/j/2KxfDVPP8prt5ecTZQi2rSpIidAKDt3xIsu49JjvvgJR5U4iajRTjXexzi4zr
/XOgzI0mVG9Il7BU22kgeRpk58kMdF15CR0qNOwmlpYHxSytjda78zJdaDOVBVUb
7A+6Ae1YTLp1hMEHFiE2OcnxClwtCTO8SRLiEW3SoZrvfi/+WrHeIZtD7ddmw6OZ
IO6EqAQ4i0eZHSCwfDJ8Yu4np9eCU360ccexVfsyIaoprGHJlc7CdQazAqRNnXnQ
KRVc3IA751EoHUURxtiV0CM6JHqJ8Be6M/XLHOhztb0gI6nbf6YuMvHJkSZT03iu
oRpiMS3HNT671ijzPIy2Ql/+6St4YHQCVIZCAoZbmp+VIFR2GZk9In9PoAjHImiF
wQXcmlFjYNJjFbD8YWaix0dZ5YZbP26sCgMi0qqp1jJLtsB911s+OmSvT94nrvgR
BW+TeJNQMgvcZBtKjDGNwNgBEga4SAU8FwQUAOiDC228Mbf/CcC8Eib2a0rSyxhy
tpnUmQU8oCmPG4dMSD3E2yY0nhiGoMDqrVZrhDwtG/k7yHXg+iidF7HrfhA0JLYf
mzOlkJKpXasFCjOmJeNvCsDu56Db+qFbanSnTNnVRHrCVAvJOHHGmLgBIVRsFf3N
hdaKjk35yyZuQ1HFrDoD7LyEK6M24I+NfmKz56StAOC/cswwz4KXp1uCC+Wpynil
suBdpq7Qa43L3Bx2WO5taaUPcI0qoGH0VPjqIf7upVw7gvvGPnOV8gZl6hWhbXgZ
IbzRNgZa8JiyuX7oXSQzCqs5hV7F7yCTnLGPprmZsOUv1R6ntWtC3dm7Njm7fGEm
oLNxdx6xPz8W0AB4RtAaulPYBQ8mT2n+BcZ3Lk9rQNeur0/13GXeqSE4nQiwQlgU
qY9y+ICOefmpfqV/SGHJ3hPOV4WDP3d2O2wwxCxvvLtjbQq6FdxGtkpBqtc/XYTB
ey4LCqNEU0ybEMRZC06/MOs7Wg1hTGBKsA38M7NIn4JzJYRasrkQxOTMik64R26l
1Y7NG5e3fRXaucHTX3fMMLv5dRRmHyjkqsEQS+O8hDsaFYmSnCTx2QFGp8FnHQq1
6qpyrYaCxEbfUWW4qyF2+T/AI1QV7pS1TiW+hoHaNvk/GNcsB9O7WX/5TonldUoW
Ktoh5Ji8b20TR7RgjcLalG6xIh6RCV5eXo9xht4n5JcrUHqj2l5S5F1dcdsmPdlk
m/z4ZGiORKtiKEOEmsMMrhXH1LQy5m3XMtXyF1nIYepEaB+oxxYZgFhDEl30xS9L
HtpbDWwSdPtHwAxSltbwLiwGMaHe5eADlIyE5eiuE8FhwdQXcUl5kfIQrYXwBRKr
JdyjQLticndssWSfOSv8XW36A8AjWGlfqJPYxl5lLdOZdVHXhBCo3AmwcJSQ/Irb
F8lZzD5gZE0vhgIiPOMFmwtd+oy6hawtOpGJ7U2kr5aDjxwWxff30DT2qS3HNm8z
yf5QF1P/7Ja+DHC+ZSlqzWEA2RlKuHOJeodXz5YGguxZcbLaUT1ogBslHeQD/pHy
LSAlz7s/86ItYLDZYmHLtj7iHPkedEcNvtX9OyxDi9cUsFNDMNfsmgQMowR7M8e2
sMfxCzstmTO6X4zTULn/2G17kGYszu3YbXck5rb7E78Df1oikt1yFar8AsWcqTf4
2kMt7t6yVJzLMQ5asrCDcfDRgoahjSpldVBnMlqu74HQMWNdtvxnGy59pBEU7O/M
kKMN98vSjW2q0v3+lnyiwcWSpJNUO2ZdExURkcuiyW4EvPrsGjwBVQ1MtEHwX2iy
ej17UHtIPfVSNw+BAe5IEKOteQzK4M2Q6YKDrQQvjfKYHVHTYTDhAgvX8bJpBWQh
QCFlvvlwGbgoj5ylx8uH7i7Qf7G4bzPNtdaMqPQ9nw9K4Qm3iix0NfjSqEFwDfRh
XUnmmc0ybe7w3t8eUfKsdjDHjUBAOs4qJUwzhjJIvxr0XD3CS0xf7X9k2Wpvg2Bq
TNRRWkANDGu6kUx8dfqtBVtE4Dxn6SNABUbYBIxmfGA3EnXdp3xSKZ/HCmhNCOwi
VlqcTn4qPpaDXooHGc5FLDJxBX7e7hsmj+rhgkJlksPS9KfrdC0cFI1KJPU9qBVi
RucQktSjtCy+IYicxbVzwtIjZ5K9IZjYbEXN3N3rl/kuChqlSySkt0DTDAA44vHI
apuLxTIWbBbTor2Ki2EV028yUJrDcVZftvkBZQvpacgLTH2S2kqHwdHs1YcwK3nE
JQbyhPhoZ+wX5ix2T97kNcMB7ODoFvhOh82LT63Rtd+WPn+xCaVBShQTcjIq+iNl
Fk3efXTKjC+xupe2kEFQt3RP4DjKyS5cOreuyvrhdXpYFVTnFAwJWmc52W71bDvW
4yow6HHgUTCCg/zMkB8w/AGv8HvN5NrnjSqUPTGaHtArV6rtVhqJgnTT3hTUlEOI
kc7M1QHWUKv6XyUjpjiGGj6Ew/MkVd4VArFTqlmizgdHSfwtY25F/AWgGMX858j2
0LoqJL+oxeu3EFNVgA1geoKZyWdaYX6Z9MgTnoBuVwhCCyOQPVl+Zjfzr3MOXp3j
r4U8wRSyS+aBA85FfdWdqONsgnEQ/uY2nxLuAwdlW5fPRG8rMR3d2rBiHV52q7fa
5SsjoQNXML+9r3iyeANELd/XoR3/khkYWj8c5tl+4nDcL/SwyekhVDj2tCZE/2PK
qLmkQq7yCPLLxZcWWXNRKhn+xu2epaa9PbySIIdcARZBrWeBKsUEq3aqk+fg88NA
hhLXTYGr3eL4q9fny6u7a4PrcoNyRaBMb7zZL9Ls/PlQri0RGmCTmOdyssvSPoMF
TlAF1eyJJ9aAroS16Suq9Sz9mWZoLC86BhbWoA7GwHzHIkTpwjM1Wxp26hRbrkXE
hRe+/2B8o1Fjxh53PdzQPq2WfrnwGDMxak+aF2UqVHfYhIXSbn8vlJEyEStgt4t2
uibyn1XRH5WmwqM94vBAyjd/aCVgHGgl341Ey1136Fz87h6W8XfwHSH5Wuh+0/Rj
vz9XUrtkEsCn3oRW/ZxcWvNrv28YUpiKFUUFUJ23xg5HTLfk8hRpIQGL66QZzxqY
a1z87PEwRzB2/U5bVEgfR1bRTn8sPx4nqY70Rg7aFwPGhz2bpJ4ePkq07pJ5NJIz
tE5974WO11l5eD4S3af2Neo27RhCqrk0hFErAwe0ahEE/+ZV26825U1h0E3WoYYD
pOc/GOt9OdWmCdUQhKWmbH2GULxaEmVn0zzfApwkYJrwV6ma65Z8Fkvl/BSNUgqm
vDkwkpoqVq7ce0oyB/E7Pzho6AhumFSQS92DIRMlXYncInIZOQyX/0s0ljNRFBfX
M9gruY5pqTnPXjj2znO9ml1xRu2PiS5iPi3dPPiRYQmvLw97/7QimDNCRQR8BoyP
lioDIx7SxAmUDQpo76pLJ5/ORMs5rVPVeCk3NVLLXwsJp2v6rUORGBHLh6IfHxs5
XXpELhWkPvXXngfcvYBJFT3HCRbf0Xzw7T4t+3bYArRhvY//GWZxzIVLhp7b62yr
HSf2gpCGVgMi0vt8lHSDbTHl2uvNe3++mkCMhvIWe4UX24iZdwNbmyuQTpvQ12+6
wMzhAVLUTXAAG7m10pq/9Fetprr1U9gSOobMs2642weoRz/8y/d84vcxlALK95LM
prolkaFhiWBMsjhdmWjqBSuYG0vXqoXUbtRcIl4zo6X+L5xIqCuFPxmPqDnNUddI
AFIyM4bzEKBYTzaM+yuNiVlMLsn8oMEzZRLpmLk0v5SwklWo5oBNALBnSZQzh4T3
5QxV9lekpRq9S48pexZ5P8iwS8SbfpdbgS8GwC3N1fJVEAV0C9e3+ocYKN0Vus/l
b9Tb8ce1WLThxHdMe1px/Abk5+AR9zOEwwiW2m+V9lVGikkQYScJtMyX+JHzGtmK
BsfP/nlali+6EgxPWfFauynVKzixWH5g77Xhmma2etNb4v5NWhD+X6Uqpu8DN27j
0xiNdOths+lJVyWhVpLWyyarYp0kLxEdKWH2lhpSNHD70ZBYxhpIQuFpiB7oCZIy
onTapHQf3/tYSfPBUz3+sE3YmYTYEjjROCIF8SWoEIrr0ycoFQ6sHTxkwudA08Wf
mzTtzCBervBaXJIO89GPR/+OUJX7vRP4WHKR7pmxmuHbAXqqmJfhf/Yf2fa2MPxE
CSeVBkSpawYTgulSHhohEwD87i6CnHpVKNa0kU4yA1bI4R5kS9VmDZxGZ8F/62Un
DDJKzB5MQ2LtrfrIH4MFMkp3wyemFHFkbvNeqQsag+NVH5iDh0rBR1tkSOvySv/g
OmjqgL7V08zwb6S9ncPGLkkF4gzwWGI35Iu4Ie415b3xqGcpnKWNV3xBDjbbur7O
10EbJMAZOWPnThwPFfG6fKXNCgekH2XyerZSIwyCRcih3ZrT6Qe6P/6mMvKIK9rh
PKMpztwZAeNk/uqmUE8ee8lmCvm4AN2BiW6XM/P6wWNNayumh6a2EfSsdNbDyMYI
eRO3vgTPl7Ap3UVySJy2jg2maHJfQgIQTVpCC1Uzc3XUebbnuXSk6kuC8DcOzK48
oCX6TIRMy624c++DLU4BVKIi5wCMpLl4SfB0DrYkRiL/g0inBUjliam+Sz0Ji5M4
tl3PwpRzQaonGdni2L4/tDRaHGlAFeE4qgCJFj9Sc5hU9+7Krj8MtjsojcAO1FCZ
J4oiM88eyC4uJwZjRXBC0a9GtpgRYgcLjzhv8UKeufburonkJrSKmJSaPi7fZ9Y3
YuD9eDtcxJMjyXZhp0BggVrUrnpWq6YpOBYOieLyy5FhlRqOkHTP4sowiJsSs30h
/3A5O2FGMGTsw1Qd6hVsMkxV1mR71slwB4+0Z9ikPTLltzKyZWBGODDYR8oS8psC
eJZ/Wm1/laKY7AR8agB4nobiUxzsMdeiPCxAdoLxB2+9USMR2WuA5ayHvt9Nuiqr
X4vUmzidszxywwCkdFXCrYiLqxQ+cBTa5+JGFZvc03u1cyZCFbaGXEO/9wch6Zd+
XZqyXnmzRT+LxEvXrSH8lI2CRo9YYcgNsLmpocDxykOGt10qup9LAZy17GyOv88z
QIXq9XBluX8TzlUPQEhnFM+r1wMECJT4ozFAuhQLDqY9rl884KF9agZWr9sn5Ujv
ACTHDbyA6SnfW449zT5QdVRK+Y4jJvxk6Ub6ARBLpXS5abBNB6plOJR3N0v63HNP
Y/EDNokDbTmJCm1GhR53yUqzjecKiHs6HHwbOTXZQPFHz3g+uDTDK88uUC0Ti2Ls
rJEgQKvaoDjMkBh/RG1YcwSsRXzZbC3tBtf0K7wyO6lPwct5pYkeXnukgRUfEc4/
IezcPxyl0gdSwdE//dK4eq6URVya6HpCvGmZcl+/Ga2rXrIW3za8uIu4RKdp76u5
fm6RIKe6jGBdSaCvq1HIyfWcodXXZ6XeHrGyaYYPtamXPXzkUSmGA0AW6JKPeWWB
5RxSOZytPDXnyOWBe37SfrttbanYG7WCOMy8kUbRpwLDB9r5nIPC0ysy6NDB60u8
5dSaQTfNOBPa1GzYJUejWhwGvuEU83c0Xd42LSuVUmvImoa3b6/594ojcgn6pDho
WNOh5xFpjMnKzbPQITc95qCCBPjWenZW5qEPnrjGfPHH5xffudMDqsfaXnC4d1Tm
6dftfXHZYzEiu4IeCmm3cYCPs2F40n72Vv344JTjC/tQlri2VShf0iK+7nmiB/cG
2iVIcQJmiInqOIVFyo+sY3QdjRpH3WF96Nb/GoyQILFeoyFZRi+/9U3G/vCwZo8O
L06dWFV46oCe70LpDVTHp12+1EZsPVtnv3WulKirT+1Xgdwjy96PE7pIjMbJKAYA
x9FfDhQnh0U/AT5E+knZl0GM+VTBko8tr1QbpS3zIi9UkRe10lwCPYxrHHu+625r
bFk8idkeUQAYKavZKnG/xS9UakbAF+slxCZr0GW+bc3u7Rx3QLG3VW4MUIgfVlPg
hM7ymURGz0UuqVh/4GLNoCPlE4S7c9zHRU5XHqONnnABWgmjIeanngZXUnqYY2Kp
Mbb/fkm8D+K7NFIhWuJtgcWAnVOAb5HR+z8EW3WgAgxsGHLxiUhFnMaRFduH+M//
m9df7rRKt82SFNFc2boFQ7MF70zKtD70rAagLLOB0anJZZM3zQ2FHNX9Chzn4yU/
XpsHdqbtLdFK5t92/kVpUXi53JkFrvPimDQH0seJBJPyPzpFJLkUZwE2jt9fCTjV
21bDzw5zYscfegOsXagkMFhxLTfvJhwXytZBPBEWDvyMHFKEXFNgXnogiQKv1UDb
8/tsgfWn50Ltyw3ah/ONxNUlA8jvRZTBXif3A4iUhLdYDkyN4F1XMRisCIWSMSD8
loPLn1zqK/9ILqHxiXc0QJGynHVgxE/nQ52wUjnOhHVE2KLpm9bphOSyP1TIs1RU
EGtOnA5hRDld3oy3GzzPXew1OfU+3YPBuwtbl8GojuXr3DhaLR4T3T9MaB69c0Ui
wdDvh98Jo7wh2kDVQXLRSjLwyscmIS+IBavUlYnp7969GSoHjWu5q7LrZiluvYQx
dzWP/m23WzR6dkhAfdtiuKxA13VnLDLN5kT5569C0WOxi2DAPayb3l6DtCPnQpgb
X8zLVzlKFJFZsJ8vJ57kVJZ42bGumuNoxnTv2Urxu/82jtXFdZhlhgYOm8X4fAWO
zr/JpQsYi+KRZVHM9tl9L2KIIyqCRrLz6ga7cwdRTLXBKVvizx686muqCqZ3jOIH
LxiNyDkr/PYL88X15vKdP+tl9OIjbi+LuRBqZbJusz7hJmcoj+oT56GEegjjI8Ol
E6lZkEipJUfK4GlOtnYvu0UGHwzobNwCZ4ae6cQDLM3P9OsHgDeYOA8I1UA1w4R5
Z7JNP8waCNomLRpp151naFDtSxfEiHcT+gRkhShndQlr/V7SPvMoZNw0ohFW7gw4
YsukrHbo2oYUxuOySy+k+2pS7vgMPNfeVW7QF9dVvqvAqQf3Yu2ev8hBp29hlDSc
M+XySsIsfRCXVDCc5QS8Atwk4F8xrg2uk87TB103Q2KqgrWQ2xuk5andanb++GHw
fjOz6+4vjv+KKxKlodiaGp5e2iyr9WEGZdtKUaG4gLiXrVuw9tlUFAA1Ca5pMy2B
+h2s9Jc7kerLLekarcU2IBF3rKfpL69es8xWicJJn9Fvb34LLGi3nhmo3IlFzfct
P4nZMMAqQ/GPbAbWjNyPjKv4c5cIfC0+2kG4nobDqWyP3pgdv5YyygTEefNjpCPP
I78m5hU2JhaxYfXzcELtSLFrFOqn7mREin1Gaqj6tiHjsfqKAQIQYWF+X4eobJZM
ZiNrbhzfPGkBxXgYMVac8jyh6jYQJZUoq+0rlALckx1Vw/9BqX03eMpojCPwLvqw
LGAJGH1QYWbgRaxO9eJ+TV0lAp53YnTzHPouatZ+E6iA+kn7MEa0iAhqzBQPU0LG
FHg08g5KLMQsLc4xj7tOzst3Litt61+0TIF0Wo1V/JNIvEz2LH3vQRHCz42VRtV2
MgqSH8/kH6R1laR2lDX3FgBVbJoLYRFhe9E0aaVyFcXF23hjRc5PpJYt8LfvnF6H
wiLG0cxc0YEWX1cm6AzK40OyloPZJBlwos+QXJMeE9/OC5wYPR7YIBSjsbS9rws8
u10aL32LrdaFkrmVOK+NWbdfH2K/NMJSPIQFCgGv6UjfsynW4YSu/HHm7+Kq020w
qoouMDE7bn33KuhMpSsIBRcSTD01Afh35FWuD3/ruGmV5DOfC4YpLEwtQFU+oC15
YFd61jllyeJO9oxcE6Z/k7986+labJ2c1EEAoOdwsPdiuvaI1z8N+4Q0e30gxe91
TnL83suTfKM0vdRSEWupApq5uC7HH4daAmy1v3NEbCuC0ipTZdTB8vr+XN6Kzl3Q
0RUqA8d6N9GbhIM/Qvc+FF5rft7TWP6PrHS+3scfH9tL/7FozXbr92HKUMoGkRbY
A069syUohs4Y/qjnxRoHpJ5CmjBk/aTQ6yFQuGrGTEcu6Oe7XV6fyuiQONu0Fsaj
kS8n90bWiR2ZodZznTwZBZA5FwBgSI1n7SJxXOS0RoVZML1/Yn88zHrNAvxehTSy
H8SG6dUIVrDOjrqJKEl3wrfT0TQG4/UNqSRJy+2xiG2z8AnneaUuDxKGk2RLya2+
tDpktV50baMI+E5wbWrIa+KWPhMn2n72zozuaZ7yhoWSGcTCs9dCqpsq6fNWr6c5
5FYo2XZWY+Ba9Z3KHhErwDuTDdl/KfSMqRbeDUflkN13DVogMIqDwVLfAYv98VAq
/fbWQL34l6mEpdJdE8DZCL9vFNxpGufBlJGTfiv1GbWwtecpcCOi/jeal/iPLpXR
i2VDJQC4Cwo52bOhcthIMFZiu3ZMRiNCUfkugmjcifeCAIQh6ErASXyIk7A/w0SD
ZYmAW/JgQfqIczZPsifVku+vqwS0BaTkMVAFDw4nFl1HnAQ7HghayItT+g+CIH0B
Wcy9q15Ino1TGdeKcD24GuRDXbWvfuKLizQ79N4zSaxZ42tp/ZAIxP5xApND8v/r
y24kkXE4fMPWbmrO+kMR/4/H9A4+iMisKpjKfeQofk4esJWcvf4a6HDtQ34k7euT
6Om9Oc093ruKhN/RSb9S183/rDUIgcvKVAIZAaZOfZD5iMQ7rsqChglBtR0NVXAL
JcUXaU09okwSAb7ppPc7Ue2+kX7rqjrUBkk9kg7qL9qkCr2jkJNuU+0FvtEkNuA7
s7waBUTqqquVtUKQ7alOhRaNVTHWavztETcZdcLWBkq2RTWxCO2MtSZQX4T7pwxc
pZ5PVZLRfom9BI5Bp43F3jG07Y6smT9LGKR37F9mP4eWcgLdQ7KACVbVlO82KmBs
J/JMfylT/kvIazgqRaefxOKGk+EnV5bewoXjOEBqiai3w6eIwck6d9rS6UKWg5/G
CKgclqViJ4x6TBVM6Hao+Wr4q7rBCtAOop1VlkwVteVKrk2IreJzhlBPRLTCi8RI

View File

@ -0,0 +1,49 @@
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES
CLANG_CXX_LANGUAGE_STANDARD = gnu++0x;
CLANG_CXX_LIBRARY = libc++;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_DYNAMIC_NO_PIC = NO;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
CODE_SIGN_IDENTITY = ;
DEVELOPMENT_TEAM = ;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
TVOS_DEPLOYMENT_TARGET = 9.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
SWIFT_VERSION = 4.2;

View File

@ -0,0 +1,11 @@
#include "Base.xcconfig"
BITCODE_GENERATION_MODE = marker;
MTL_ENABLE_DEBUG_INFO = YES;
COPY_PHASE_STRIP = NO;
ENABLE_TESTABILITY = YES;
GCC_OPTIMIZATION_LEVEL = 0;
ONLY_ACTIVE_ARCH = YES;
SWIFT_OPTIMIZATION_LEVEL = -Onone;
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1;

View File

@ -0,0 +1,23 @@
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator;
TARGETED_DEVICE_FAMILY = 1,2,3,4;
COMBINE_HIDPI_IMAGES = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier);
PRODUCT_NAME = $(PROJECT_NAME);
APPLICATION_EXTENSION_API_ONLY = YES;
INFOPLIST_FILE = KeychainAccess/Info.plist;
SKIP_INSTALL = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = @rpath;
ENABLE_BITCODE[sdk=iphone*] = YES;
ENABLE_BITCODE[sdk=watch*] = YES;
ENABLE_BITCODE[sdk=appletv*] = YES;
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks;

View File

@ -0,0 +1,9 @@
#include "Base.xcconfig"
BITCODE_GENERATION_MODE = bitcode;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
MTL_ENABLE_DEBUG_INFO = NO;
VALIDATE_PRODUCT = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = -Owholemodule;

View File

@ -0,0 +1,31 @@
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator;
TARGETED_DEVICE_FAMILY = 1,2,3;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = TestHost/Info.plist;
PRODUCT_NAME = $(TARGET_NAME);
CLANG_MODULES_AUTOLINK = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.KeychainAccess.TestHost;
CODE_SIGN_ENTITLEMENTS = TestHost/TestHost.entitlements;
CODE_SIGN_IDENTITY[sdk=iphone*] = iPhone Developer;
CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application;
PROVISIONING_PROFILE_SPECIFIER[sdk=iphone*] = iOS Development;
PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = KeychainAccess Tests;
DEVELOPMENT_TEAM = 27AEDK3C9F;
PRINCIPAL_CLASS[sdk=iphone*] = UIApplication;
PRINCIPAL_CLASS[sdk=appletv*] = UIApplication;
PRINCIPAL_CLASS[sdk=macosx*] = NSApplication;
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks;

View File

@ -0,0 +1,22 @@
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator;
COMBINE_HIDPI_IMAGES = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.kishikawakatsumi.$(PRODUCT_NAME:rfc1034identifier);
PRODUCT_NAME = $(TARGET_NAME);
APPLICATION_EXTENSION_API_ONLY = NO;
INFOPLIST_FILE = KeychainAccessTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks;
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks;
TEST_HOST[sdk=iphone*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost;
TEST_HOST[sdk=appletv*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost;
TEST_HOST[sdk=macosx*] = $(BUILT_PRODUCTS_DIR)/TestHost.app/Contents/MacOS/TestHost;
EXCLUDED_SOURCE_FILE_NAMES[sdk=watch*] = *;
EXCLUDED_SOURCE_FILE_NAMES[sdk=appletv*] = SharedCredentialTests.swift;
EXCLUDED_SOURCE_FILE_NAMES[sdk=macosx*] = SharedCredentialTests.swift;
DEVELOPMENT_TEAM = 27AEDK3C9F;

View File

@ -0,0 +1,5 @@
source 'https://rubygems.org'
gem 'rake'
gem 'xcpretty'
gem 'xcjobs'

View File

@ -0,0 +1,19 @@
GEM
remote: https://rubygems.org/
specs:
rake (12.3.1)
rouge (2.0.7)
xcjobs (0.10.0)
xcpretty (0.3.0)
rouge (~> 2.0.7)
PLATFORMS
ruby
DEPENDENCIES
rake
xcjobs
xcpretty
BUNDLED WITH
1.16.3

View File

@ -0,0 +1,488 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
140F19621A49D79400B0016A /* KeychainAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 140F19611A49D79400B0016A /* KeychainAccess.h */; settings = {ATTRIBUTES = (Public, ); }; };
140F196F1A49D79500B0016A /* KeychainAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140F196E1A49D79500B0016A /* KeychainAccessTests.swift */; };
140F197B1A49D89200B0016A /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140F197A1A49D89200B0016A /* Keychain.swift */; };
142EDA851BCB505F00A32149 /* ErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */; };
142EDB041BCBB0DD00A32149 /* SharedCredentialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */; };
148F9D4A1BCB4118006EDF48 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148F9D491BCB4118006EDF48 /* EnumTests.swift */; };
14A630181D3293C700809B3F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A630171D3293C700809B3F /* AppDelegate.swift */; };
14A6301F1D3293C700809B3F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14A6301E1D3293C700809B3F /* Assets.xcassets */; };
14C3A6781D32BF9C00349459 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; };
14C3A6791D32BF9C00349459 /* KeychainAccess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 140F195C1A49D79400B0016A /* KeychainAccess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
140F19691A49D79500B0016A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 140F19531A49D79400B0016A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 140F195B1A49D79400B0016A;
remoteInfo = KeychainAccess;
};
14C3A67A1D32BF9C00349459 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 140F19531A49D79400B0016A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 140F195B1A49D79400B0016A;
remoteInfo = KeychainAccess;
};
14F0C1991D32A160007DCDDB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 140F19531A49D79400B0016A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 14A630141D3293C700809B3F;
remoteInfo = TestHost;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
14C3A67C1D32BF9D00349459 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
14C3A6791D32BF9C00349459 /* KeychainAccess.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
140F195C1A49D79400B0016A /* KeychainAccess.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KeychainAccess.framework; sourceTree = BUILT_PRODUCTS_DIR; };
140F19601A49D79400B0016A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
140F19611A49D79400B0016A /* KeychainAccess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainAccess.h; sourceTree = "<group>"; };
140F19671A49D79500B0016A /* KeychainAccessTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainAccessTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
140F196D1A49D79500B0016A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
140F196E1A49D79500B0016A /* KeychainAccessTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainAccessTests.swift; sourceTree = "<group>"; };
140F197A1A49D89200B0016A /* Keychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorTypeTests.swift; sourceTree = "<group>"; };
142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedCredentialTests.swift; sourceTree = "<group>"; };
148E44E51BF9EDCB004FFEC1 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = Configurations/Base.xcconfig; sourceTree = "<group>"; };
148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = "<group>"; };
148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = "<group>"; };
148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Tests.xcconfig; path = Configurations/Tests.xcconfig; sourceTree = "<group>"; };
148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = KeychainAccess.xcconfig; path = Configurations/KeychainAccess.xcconfig; sourceTree = "<group>"; };
148F9D491BCB4118006EDF48 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = "<group>"; };
14A630151D3293C700809B3F /* TestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHost.app; sourceTree = BUILT_PRODUCTS_DIR; };
14A630171D3293C700809B3F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
14A6301E1D3293C700809B3F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
14A630231D3293C700809B3F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
14F0C1961D3295C4007DCDDB /* TestHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TestHost.entitlements; sourceTree = "<group>"; };
14F0C1981D329832007DCDDB /* TestHost.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = TestHost.xcconfig; path = Configurations/TestHost.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
140F19581A49D79400B0016A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
140F19641A49D79500B0016A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
14A630121D3293C700809B3F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14C3A6781D32BF9C00349459 /* KeychainAccess.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
140F19521A49D79400B0016A = {
isa = PBXGroup;
children = (
140F195E1A49D79400B0016A /* KeychainAccess */,
140F196B1A49D79500B0016A /* KeychainAccessTests */,
148E44E41BF9ED6D004FFEC1 /* Cofigurations */,
14A630161D3293C700809B3F /* TestHost */,
140F195D1A49D79400B0016A /* Products */,
);
sourceTree = "<group>";
};
140F195D1A49D79400B0016A /* Products */ = {
isa = PBXGroup;
children = (
140F195C1A49D79400B0016A /* KeychainAccess.framework */,
140F19671A49D79500B0016A /* KeychainAccessTests.xctest */,
14A630151D3293C700809B3F /* TestHost.app */,
);
name = Products;
sourceTree = "<group>";
};
140F195E1A49D79400B0016A /* KeychainAccess */ = {
isa = PBXGroup;
children = (
140F19611A49D79400B0016A /* KeychainAccess.h */,
140F197A1A49D89200B0016A /* Keychain.swift */,
140F195F1A49D79400B0016A /* Supporting Files */,
);
path = KeychainAccess;
sourceTree = "<group>";
};
140F195F1A49D79400B0016A /* Supporting Files */ = {
isa = PBXGroup;
children = (
140F19601A49D79400B0016A /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
140F196B1A49D79500B0016A /* KeychainAccessTests */ = {
isa = PBXGroup;
children = (
140F196E1A49D79500B0016A /* KeychainAccessTests.swift */,
148F9D491BCB4118006EDF48 /* EnumTests.swift */,
142EDA841BCB505F00A32149 /* ErrorTypeTests.swift */,
142EDB031BCBB0DD00A32149 /* SharedCredentialTests.swift */,
140F196C1A49D79500B0016A /* Supporting Files */,
);
path = KeychainAccessTests;
sourceTree = "<group>";
};
140F196C1A49D79500B0016A /* Supporting Files */ = {
isa = PBXGroup;
children = (
140F196D1A49D79500B0016A /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
148E44E41BF9ED6D004FFEC1 /* Cofigurations */ = {
isa = PBXGroup;
children = (
148E44E51BF9EDCB004FFEC1 /* Base.xcconfig */,
148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */,
148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */,
148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */,
148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */,
14F0C1981D329832007DCDDB /* TestHost.xcconfig */,
);
name = Cofigurations;
sourceTree = "<group>";
};
14A630161D3293C700809B3F /* TestHost */ = {
isa = PBXGroup;
children = (
14A630171D3293C700809B3F /* AppDelegate.swift */,
14A6301E1D3293C700809B3F /* Assets.xcassets */,
14A630231D3293C700809B3F /* Info.plist */,
14F0C1961D3295C4007DCDDB /* TestHost.entitlements */,
);
path = TestHost;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
140F19591A49D79400B0016A /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
140F19621A49D79400B0016A /* KeychainAccess.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
140F195B1A49D79400B0016A /* KeychainAccess */ = {
isa = PBXNativeTarget;
buildConfigurationList = 140F19721A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccess" */;
buildPhases = (
140F19571A49D79400B0016A /* Sources */,
140F19581A49D79400B0016A /* Frameworks */,
140F19591A49D79400B0016A /* Headers */,
140F195A1A49D79400B0016A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = KeychainAccess;
productName = KeychainAccess;
productReference = 140F195C1A49D79400B0016A /* KeychainAccess.framework */;
productType = "com.apple.product-type.framework";
};
140F19661A49D79500B0016A /* KeychainAccessTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 140F19751A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccessTests" */;
buildPhases = (
140F19631A49D79500B0016A /* Sources */,
140F19641A49D79500B0016A /* Frameworks */,
140F19651A49D79500B0016A /* Resources */,
);
buildRules = (
);
dependencies = (
140F196A1A49D79500B0016A /* PBXTargetDependency */,
14F0C19A1D32A160007DCDDB /* PBXTargetDependency */,
);
name = KeychainAccessTests;
productName = KeychainAccessTests;
productReference = 140F19671A49D79500B0016A /* KeychainAccessTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
14A630141D3293C700809B3F /* TestHost */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14A630241D3293C700809B3F /* Build configuration list for PBXNativeTarget "TestHost" */;
buildPhases = (
14A630111D3293C700809B3F /* Sources */,
14A630121D3293C700809B3F /* Frameworks */,
14A630131D3293C700809B3F /* Resources */,
14C3A67C1D32BF9D00349459 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
14C3A67B1D32BF9C00349459 /* PBXTargetDependency */,
);
name = TestHost;
productName = TestHost;
productReference = 14A630151D3293C700809B3F /* TestHost.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
140F19531A49D79400B0016A /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 1000;
ORGANIZATIONNAME = "kishikawa katsumi";
TargetAttributes = {
140F195B1A49D79400B0016A = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 1000;
ProvisioningStyle = Automatic;
};
140F19661A49D79500B0016A = {
CreatedOnToolsVersion = 6.1.1;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 0900;
TestTargetID = 14A62FFC1D32922C00809B3F;
};
14A630141D3293C700809B3F = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 27AEDK3C9F;
LastSwiftMigration = 0900;
SystemCapabilities = {
com.apple.Keychain = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = 140F19561A49D79400B0016A /* Build configuration list for PBXProject "KeychainAccess" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 140F19521A49D79400B0016A;
productRefGroup = 140F195D1A49D79400B0016A /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
140F195B1A49D79400B0016A /* KeychainAccess */,
140F19661A49D79500B0016A /* KeychainAccessTests */,
14A630141D3293C700809B3F /* TestHost */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
140F195A1A49D79400B0016A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
140F19651A49D79500B0016A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
14A630131D3293C700809B3F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A6301F1D3293C700809B3F /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
140F19571A49D79400B0016A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
140F197B1A49D89200B0016A /* Keychain.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
140F19631A49D79500B0016A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
140F196F1A49D79500B0016A /* KeychainAccessTests.swift in Sources */,
148F9D4A1BCB4118006EDF48 /* EnumTests.swift in Sources */,
142EDA851BCB505F00A32149 /* ErrorTypeTests.swift in Sources */,
142EDB041BCBB0DD00A32149 /* SharedCredentialTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14A630111D3293C700809B3F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14A630181D3293C700809B3F /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
140F196A1A49D79500B0016A /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 140F195B1A49D79400B0016A /* KeychainAccess */;
targetProxy = 140F19691A49D79500B0016A /* PBXContainerItemProxy */;
};
14C3A67B1D32BF9C00349459 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 140F195B1A49D79400B0016A /* KeychainAccess */;
targetProxy = 14C3A67A1D32BF9C00349459 /* PBXContainerItemProxy */;
};
14F0C19A1D32A160007DCDDB /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 14A630141D3293C700809B3F /* TestHost */;
targetProxy = 14F0C1991D32A160007DCDDB /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
140F19701A49D79500B0016A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E61BF9EDCB004FFEC1 /* Debug.xcconfig */;
buildSettings = {
};
name = Debug;
};
140F19711A49D79500B0016A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E71BF9EDCB004FFEC1 /* Release.xcconfig */;
buildSettings = {
};
name = Release;
};
140F19731A49D79500B0016A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */;
buildSettings = {
};
name = Debug;
};
140F19741A49D79500B0016A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44EB1BF9EEB3004FFEC1 /* KeychainAccess.xcconfig */;
buildSettings = {
};
name = Release;
};
140F19761A49D79500B0016A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */;
buildSettings = {
};
name = Debug;
};
140F19771A49D79500B0016A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 148E44E91BF9EDE4004FFEC1 /* Tests.xcconfig */;
buildSettings = {
};
name = Release;
};
14A630251D3293C700809B3F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14F0C1981D329832007DCDDB /* TestHost.xcconfig */;
buildSettings = {
};
name = Debug;
};
14A630261D3293C700809B3F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14F0C1981D329832007DCDDB /* TestHost.xcconfig */;
buildSettings = {
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
140F19561A49D79400B0016A /* Build configuration list for PBXProject "KeychainAccess" */ = {
isa = XCConfigurationList;
buildConfigurations = (
140F19701A49D79500B0016A /* Debug */,
140F19711A49D79500B0016A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
140F19721A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccess" */ = {
isa = XCConfigurationList;
buildConfigurations = (
140F19731A49D79500B0016A /* Debug */,
140F19741A49D79500B0016A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
140F19751A49D79500B0016A /* Build configuration list for PBXNativeTarget "KeychainAccessTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
140F19761A49D79500B0016A /* Debug */,
140F19771A49D79500B0016A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
14A630241D3293C700809B3F /* Build configuration list for PBXNativeTarget "TestHost" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14A630251D3293C700809B3F /* Debug */,
14A630261D3293C700809B3F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 140F19531A49D79400B0016A /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:KeychainAccess.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "140F195B1A49D79400B0016A"
BuildableName = "KeychainAccess.framework"
BlueprintName = "KeychainAccess"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "140F19661A49D79500B0016A"
BuildableName = "KeychainAccessTests.xctest"
BlueprintName = "KeychainAccessTests"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "140F19661A49D79500B0016A"
BuildableName = "KeychainAccessTests.xctest"
BlueprintName = "KeychainAccessTests"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "140F195B1A49D79400B0016A"
BuildableName = "KeychainAccess.framework"
BlueprintName = "KeychainAccess"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "140F195B1A49D79400B0016A"
BuildableName = "KeychainAccess.framework"
BlueprintName = "KeychainAccess"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "140F195B1A49D79400B0016A"
BuildableName = "KeychainAccess.framework"
BlueprintName = "KeychainAccess"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14A630141D3293C700809B3F"
BuildableName = "TestHost.app"
BlueprintName = "TestHost"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14A630141D3293C700809B3F"
BuildableName = "TestHost.app"
BlueprintName = "TestHost"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14A630141D3293C700809B3F"
BuildableName = "TestHost.app"
BlueprintName = "TestHost"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14A630141D3293C700809B3F"
BuildableName = "TestHost.app"
BlueprintName = "TestHost"
ReferencedContainer = "container:KeychainAccess.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.1.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,29 @@
//
// KeychainAccess.h
// KeychainAccess
//
// Created by kishikawa katsumi on 2014/12/24.
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT double KeychainAccessVersionNumber;
FOUNDATION_EXPORT const unsigned char KeychainAccessVersionString[];

View File

@ -0,0 +1,305 @@
//
// EnumTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class EnumTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testItemClass() {
do {
let itemClass = ItemClass(rawValue: kSecClassGenericPassword as String)
XCTAssertEqual(itemClass, .genericPassword)
XCTAssertEqual(itemClass?.description, "GenericPassword")
}
do {
let itemClass = ItemClass(rawValue: kSecClassInternetPassword as String)
XCTAssertEqual(itemClass, .internetPassword)
XCTAssertEqual(itemClass?.description, "InternetPassword")
}
do {
let itemClass = ItemClass(rawValue: kSecClassCertificate as String)
XCTAssertNil(itemClass)
}
do {
let itemClass = ItemClass(rawValue: kSecClassKey as String)
XCTAssertNil(itemClass)
}
do {
let itemClass = ItemClass(rawValue: kSecClassIdentity as String)
XCTAssertNil(itemClass)
}
}
func testProtocolType() {
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTP as String)
XCTAssertEqual(protocolType, .ftp)
XCTAssertEqual(protocolType?.description, "FTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPAccount as String)
XCTAssertEqual(protocolType, .ftpAccount)
XCTAssertEqual(protocolType?.description, "FTPAccount")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTP as String)
XCTAssertEqual(protocolType, .http)
XCTAssertEqual(protocolType?.description, "HTTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRC as String)
XCTAssertEqual(protocolType, .irc)
XCTAssertEqual(protocolType?.description, "IRC")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTP as String)
XCTAssertEqual(protocolType, .nntp)
XCTAssertEqual(protocolType?.description, "NNTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3 as String)
XCTAssertEqual(protocolType, .pop3)
XCTAssertEqual(protocolType?.description, "POP3")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMTP as String)
XCTAssertEqual(protocolType, .smtp)
XCTAssertEqual(protocolType?.description, "SMTP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSOCKS as String)
XCTAssertEqual(protocolType, .socks)
XCTAssertEqual(protocolType?.description, "SOCKS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAP as String)
XCTAssertEqual(protocolType, .imap)
XCTAssertEqual(protocolType?.description, "IMAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAP as String)
XCTAssertEqual(protocolType, .ldap)
XCTAssertEqual(protocolType?.description, "LDAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolAppleTalk as String)
XCTAssertEqual(protocolType, .appleTalk)
XCTAssertEqual(protocolType?.description, "AppleTalk")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolAFP as String)
XCTAssertEqual(protocolType, .afp)
XCTAssertEqual(protocolType?.description, "AFP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnet as String)
XCTAssertEqual(protocolType, .telnet)
XCTAssertEqual(protocolType?.description, "Telnet")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSSH as String)
XCTAssertEqual(protocolType, .ssh)
XCTAssertEqual(protocolType?.description, "SSH")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPS as String)
XCTAssertEqual(protocolType, .ftps)
XCTAssertEqual(protocolType?.description, "FTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPS as String)
XCTAssertEqual(protocolType, .https)
XCTAssertEqual(protocolType?.description, "HTTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPProxy as String)
XCTAssertEqual(protocolType, .httpProxy)
XCTAssertEqual(protocolType?.description, "HTTPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolHTTPSProxy as String)
XCTAssertEqual(protocolType, .httpsProxy)
XCTAssertEqual(protocolType?.description, "HTTPSProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolFTPProxy as String)
XCTAssertEqual(protocolType, .ftpProxy)
XCTAssertEqual(protocolType?.description, "FTPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolSMB as String)
XCTAssertEqual(protocolType, .smb)
XCTAssertEqual(protocolType?.description, "SMB")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSP as String)
XCTAssertEqual(protocolType, .rtsp)
XCTAssertEqual(protocolType?.description, "RTSP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolRTSPProxy as String)
XCTAssertEqual(protocolType, .rtspProxy)
XCTAssertEqual(protocolType?.description, "RTSPProxy")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolDAAP as String)
XCTAssertEqual(protocolType, .daap)
XCTAssertEqual(protocolType?.description, "DAAP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolEPPC as String)
XCTAssertEqual(protocolType, .eppc)
XCTAssertEqual(protocolType?.description, "EPPC")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIPP as String)
XCTAssertEqual(protocolType, .ipp)
XCTAssertEqual(protocolType?.description, "IPP")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolNNTPS as String)
XCTAssertEqual(protocolType, .nntps)
XCTAssertEqual(protocolType?.description, "NNTPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolLDAPS as String)
XCTAssertEqual(protocolType, .ldaps)
XCTAssertEqual(protocolType?.description, "LDAPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolTelnetS as String)
XCTAssertEqual(protocolType, .telnetS)
XCTAssertEqual(protocolType?.description, "TelnetS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIMAPS as String)
XCTAssertEqual(protocolType, .imaps)
XCTAssertEqual(protocolType?.description, "IMAPS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolIRCS as String)
XCTAssertEqual(protocolType, .ircs)
XCTAssertEqual(protocolType?.description, "IRCS")
}
do {
let protocolType = ProtocolType(rawValue: kSecAttrProtocolPOP3S as String)
XCTAssertEqual(protocolType, .pop3S)
XCTAssertEqual(protocolType?.description, "POP3S")
}
}
func testAuthenticationType() {
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeNTLM as String)
XCTAssertEqual(authenticationType, .ntlm)
XCTAssertEqual(authenticationType?.description, "NTLM")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeMSN as String)
XCTAssertEqual(authenticationType, .msn)
XCTAssertEqual(authenticationType?.description, "MSN")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDPA as String)
XCTAssertEqual(authenticationType, .dpa)
XCTAssertEqual(authenticationType?.description, "DPA")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeRPA as String)
XCTAssertEqual(authenticationType, .rpa)
XCTAssertEqual(authenticationType?.description, "RPA")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPBasic as String)
XCTAssertEqual(authenticationType, .httpBasic)
XCTAssertEqual(authenticationType?.description, "HTTPBasic")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTTPDigest as String)
XCTAssertEqual(authenticationType, .httpDigest)
XCTAssertEqual(authenticationType?.description, "HTTPDigest")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeHTMLForm as String)
XCTAssertEqual(authenticationType, .htmlForm)
XCTAssertEqual(authenticationType?.description, "HTMLForm")
}
do {
let authenticationType = AuthenticationType(rawValue: kSecAttrAuthenticationTypeDefault as String)
XCTAssertEqual(authenticationType, .default)
XCTAssertEqual(authenticationType?.description, "Default")
}
}
func testAccessibility() {
guard #available(OSX 10.10, *) else {
return
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlocked as String)
XCTAssertEqual(accessibility, .whenUnlocked)
XCTAssertEqual(accessibility?.description, "WhenUnlocked")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlock as String)
XCTAssertEqual(accessibility, .afterFirstUnlock)
XCTAssertEqual(accessibility?.description, "AfterFirstUnlock")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlways as String)
XCTAssertEqual(accessibility, .always)
XCTAssertEqual(accessibility?.description, "Always")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly as String)
XCTAssertEqual(accessibility, .whenPasscodeSetThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "WhenPasscodeSetThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleWhenUnlockedThisDeviceOnly as String)
XCTAssertEqual(accessibility, .whenUnlockedThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "WhenUnlockedThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)
XCTAssertEqual(accessibility, .afterFirstUnlockThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "AfterFirstUnlockThisDeviceOnly")
}
do {
let accessibility = Accessibility(rawValue: kSecAttrAccessibleAlwaysThisDeviceOnly as String)
XCTAssertEqual(accessibility, .alwaysThisDeviceOnly)
XCTAssertEqual(accessibility?.description, "AlwaysThisDeviceOnly")
}
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,84 @@
//
// SharedCredentialTests.swift
// KeychainAccessTests
//
// Created by kishikawa katsumi on 10/12/15.
// Copyright © 2015 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import XCTest
import KeychainAccess
class SharedCredentialTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testGetSharedPassword() {
do {
let expectation = self.expectation(description: "getSharedPassword")
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https)
keychain.getSharedPassword("kishikawakatsumi") { (password, error) -> () in
XCTAssertNil(password)
XCTAssertNotNil(error)
expectation.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
}
do {
let expectation = self.expectation(description: "getSharedPassword")
let keychain = Keychain(server: "https://kishikawakatsumi.com", protocolType: .https)
keychain.getSharedPassword { (account, password, error) -> () in
XCTAssertNil(account)
XCTAssertNil(password)
XCTAssertNotNil(error)
expectation.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
}
}
func testGeneratePassword() {
do {
var passwords = Set<String>()
for _ in 0...100_000 {
let password = Keychain.generatePassword()
XCTAssertEqual(password.characters.count, "xxx-xxx-xxx-xxx".characters.count)
XCTAssertFalse(passwords.contains(password))
passwords.insert(password)
}
}
}
}

View File

@ -0,0 +1,321 @@
require 'xcjobs'
require 'json'
def xcode_version
`xcodebuild -version`.split("\n").first.scan(/\d+/).join('.')
end
def destinations(platform: 'iphonesimulator')
if platform == 'iphonesimulator'
if xcode_version.start_with?('10')
[ 'name=iPhone 5s,OS=12.0',
'name=iPhone 6,OS=12.0',
'name=iPhone 6s Plus,OS=12.0',
'name=iPhone SE,OS=12.0',
'name=iPad Air 2,OS=12.0',
'name=iPad Pro (9.7-inch),OS=12.0',
'name=iPad Pro (12.9-inch),OS=12.0'
]
elsif xcode_version.start_with?('9.4')
[ 'name=iPhone 5s,OS=11.4',
'name=iPhone 6,OS=11.4',
'name=iPhone 6s Plus,OS=11.4',
'name=iPhone SE,OS=11.4',
'name=iPad Air 2,OS=11.4',
'name=iPad Pro (9.7-inch),OS=11.4',
'name=iPad Pro (12.9-inch),OS=11.4'
]
elsif xcode_version.start_with?('9.3')
[ 'name=iPhone 5s,OS=11.0.1',
'name=iPhone 5s,OS=11.1',
'name=iPhone 6,OS=11.2',
'name=iPhone 6s Plus,OS=11.3',
'name=iPhone SE,OS=11.0.1',
'name=iPad Air 2,OS=11.1',
'name=iPad Pro (9.7-inch),OS=11.2',
'name=iPad Pro (12.9-inch),OS=11.3'
]
elsif xcode_version.start_with?('9.2')
[ 'name=iPhone 5s,OS=11.2',
'name=iPhone 5s,OS=11.2',
'name=iPhone 6,OS=11.2',
'name=iPhone 6s Plus,OS=11.2',
'name=iPhone SE,OS=11.2',
'name=iPad Air 2,OS=11.2',
'name=iPad Pro (9.7-inch),OS=11.2',
'name=iPad Pro (12.9-inch),OS=11.2'
]
elsif xcode_version.start_with?('9.1')
[ 'name=iPhone 5s,OS=11.1',
'name=iPhone 5s,OS=11.1',
'name=iPhone 6,OS=11.1',
'name=iPhone 6s Plus,OS=11.1',
'name=iPhone SE,OS=11.1',
'name=iPad Air 2,OS=11.1',
'name=iPad Pro (9.7-inch),OS=11.1',
'name=iPad Pro (12.9-inch),OS=11.1'
]
elsif xcode_version.start_with?('9')
[ 'name=iPhone 5,OS=10.0',
'name=iPhone 5s,OS=10.0',
'name=iPhone 6,OS=10.0',
'name=iPhone 6s Plus,OS=10.3.1',
'name=iPhone SE,OS=10.3.1',
'name=iPhone 7,OS=11.0',
'name=iPad Air 2,OS=10.0',
'name=iPad Pro (9.7-inch),OS=10.0',
'name=iPad Pro (12.9-inch),OS=10.0',
'name=iPad Pro (10.5-inch),OS=11.0'
]
else
[ 'name=iPhone 5,OS=10.0',
'name=iPhone 5s,OS=10.0',
'name=iPhone 6,OS=10.0',
'name=iPhone 6s Plus,OS=10.3.1',
'name=iPhone SE,OS=10.3.1',
'name=iPad Air 2,OS=10.0',
'name=iPad Pro (9.7-inch),OS=10.0',
'name=iPad Pro (12.9-inch),OS=10.0'
]
end
elsif platform == 'watchsimulator'
if xcode_version.start_with?('10')
[ 'name=Apple Watch Series 4 - 40mm,OS=5.0',
'name=Apple Watch Series 4 - 44mm,OS=5.0'
]
elsif xcode_version.start_with?('9.4')
[ 'name=Apple Watch Series 3 - 38mm,OS=4.3',
'name=Apple Watch Series 3 - 42mm,OS=4.3'
]
elsif xcode_version.start_with?('9.3')
[ 'name=Apple Watch - 38mm,OS=4.3',
'name=Apple Watch - 42mm,OS=4.3',
'name=Apple Watch Series 2 - 42mm,OS=4.3'
]
elsif xcode_version.start_with?('9.2')
[ 'name=Apple Watch - 38mm,OS=4.2',
'name=Apple Watch - 42mm,OS=4.2',
'name=Apple Watch Series 2 - 42mm,OS=4.2'
]
elsif xcode_version.start_with?('9.1')
[ 'name=Apple Watch - 38mm,OS=4.1',
'name=Apple Watch - 42mm,OS=4.1',
'name=Apple Watch Series 2 - 42mm,OS=4.1'
]
elsif xcode_version.start_with?('9')
[ 'name=Apple Watch - 38mm,OS=3.2',
'name=Apple Watch - 42mm,OS=4.0',
'name=Apple Watch Series 2 - 42mm,OS=4.0'
]
else
[ 'name=Apple Watch - 38mm,OS=3.2',
'name=Apple Watch Series 2 - 42mm,OS=3.2'
]
end
elsif platform == 'appletvsimulator'
if xcode_version.start_with?('10')
[ 'name=Apple TV 4K,OS=12.0'
]
elsif xcode_version.start_with?('9.4')
[ 'name=Apple TV 4K,OS=11.4'
]
elsif xcode_version.start_with?('9.3')
[ 'name=Apple TV 4K,OS=11.3'
]
elsif xcode_version.start_with?('9.2')
[ 'name=Apple TV 4K,OS=11.2'
]
elsif xcode_version.start_with?('9.1')
[ 'name=Apple TV 4K,OS=11.1'
]
elsif xcode_version.start_with?('9')
[ 'name=Apple TV 1080p,OS=10.2',
'name=Apple TV 1080p,OS=11.0'
]
else
[ 'name=Apple TV 1080p,OS=10.2'
]
end
else
[
'platform=OS X,arch=x86_64'
]
end
end
def supportedPlatforms
['macosx', 'iphoneos', 'iphonesimulator', 'watchos', 'watchsimulator', 'appletvos', 'appletvsimulator']
end
def configurations
['Debug', 'Release']
end
desc "build for all platforms"
task :build do |t|
supportedPlatforms
.product(configurations)
.map { |platform, configuration| Rake::Task["build:#{platform}:#{configuration.downcase}"] }
.map(&:invoke)
end
namespace :build do
supportedPlatforms.product(configurations).each do |platform, configuration|
XCJobs::Build.new("#{platform}:#{configuration.downcase}") do |t|
t.project = 'KeychainAccess'
t.scheme = 'KeychainAccess'
t.sdk = platform
t.configuration = configuration
t.build_dir = 'build'
t.hide_shell_script_environment = true
t.formatter = 'xcpretty -c'
if ENV['CI']
t.add_build_setting('CODE_SIGN_IDENTITY', '')
t.add_build_setting('CODE_SIGNING_REQUIRED', 'NO')
end
if xcode_version.start_with?('10')
t.add_build_setting('SWIFT_VERSION', '4.2')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=12.0')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch Series 4 - 44mm,OS=5.0')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=12.0')
end
elsif xcode_version.start_with?('9.4')
t.add_build_setting('SWIFT_VERSION', '4.1')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.4')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch Series 3 - 42mm,OS=4.3')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.4')
end
elsif xcode_version.start_with?('9.3')
t.add_build_setting('SWIFT_VERSION', '4.1')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.3')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.3')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.3')
end
elsif xcode_version.start_with?('9.2')
t.add_build_setting('SWIFT_VERSION', '4.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.2')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.2')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.2')
end
elsif xcode_version.start_with?('9.1')
t.add_build_setting('SWIFT_VERSION', '4.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.1')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.1')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 4K,OS=11.1')
end
elsif xcode_version.start_with?('9')
t.add_build_setting('SWIFT_VERSION', '4.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=11.0')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=4.0')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 1080p,OS=11.0')
end
else
t.add_build_setting('SWIFT_VERSION', '3.0')
if platform == 'iphonesimulator'
t.add_destination('name=iPhone 7,OS=10.3.1')
elsif platform == 'watchsimulator'
t.add_destination('name=Apple Watch - 42mm,OS=3.2')
elsif platform == 'appletvsimulator'
t.add_destination('name=Apple TV 1080p,OS=10.0')
end
end
end
end
task :carthage do
sh %[echo 'github \"kishikawakatsumi/KeychainAccess\"' > Cartfile]
if xcode_version.start_with?('10')
sh %[echo SWIFT_VERSION=\"4.2\" > swift.xcconfig]
elsif xcode_version.start_with?('9.4')
sh %[echo SWIFT_VERSION=\"4.1\" > swift.xcconfig]
elsif xcode_version.start_with?('9.3')
sh %[echo SWIFT_VERSION=\"4.1\" > swift.xcconfig]
elsif xcode_version.start_with?('9')
sh %[echo SWIFT_VERSION=\"4.0\" > swift.xcconfig]
else
sh %[echo SWIFT_VERSION=\"3.0\" > swift.xcconfig]
end
sh %[XCODE_XCCONFIG_FILE=`pwd`/swift.xcconfig carthage update --no-use-binaries]
sh %[find . -name '*.bcsymbolmap' | xargs grep swiftlang]
end
end
namespace :test do
supportedPlatforms
.select { |platform| platform == 'macosx' || platform == 'iphonesimulator' || platform == 'appletvsimulator' }
.each do |platform|
task platform do |t|
configurations.each do |configuration|
destinations(platform: platform)
.map { |destination| Rake::Task["test:#{platform}:#{configuration.downcase}:#{destination}"] }
.map(&:invoke)
end
end
end
end
namespace :test do
supportedPlatforms
.select { |platform| platform == 'macosx' || platform == 'iphonesimulator' || platform == 'appletvsimulator' }
.product(configurations)
.each do |platform, configuration|
destinations(platform: platform).each do |destination|
XCJobs::Test.new("#{platform}:#{configuration.downcase}:#{destination}") do |t|
t.project = 'KeychainAccess'
t.scheme = 'KeychainAccess'
t.sdk = platform
t.configuration = configuration
t.add_destination(destination)
t.coverage = true
t.build_dir = 'build'
t.hide_shell_script_environment = true
if xcode_version.start_with?('10')
t.add_build_setting('SWIFT_VERSION', '4.2')
elsif xcode_version.start_with?('9.4')
t.add_build_setting('SWIFT_VERSION', '4.1')
elsif xcode_version.start_with?('9.3')
t.add_build_setting('SWIFT_VERSION', '4.1')
elsif xcode_version.start_with?('9')
t.add_build_setting('SWIFT_VERSION', '4.0')
else
t.add_build_setting('SWIFT_VERSION', '3.0')
end
t.after_action do
build_coverage_reports()
puts `curl -L https://codecov.io/bash | bash -s -- -f 'coverage.txt'`
end
end
end
end
end
def build_coverage_reports()
project_name = 'KeychainAccess'
profdata = Dir.glob(File.join('build', '/**/Coverage.profdata')).first
Dir.glob(File.join('build', "/**/#{project_name}")) do |target|
output = `xcrun llvm-cov report -instr-profile "#{profdata}" "#{target}" -arch=x86_64`
if $?.success?
puts output
`xcrun llvm-cov show -instr-profile "#{profdata}" "#{target}" -arch=x86_64 -use-color=0 > coverage.txt`
break
end
end
end

View File

@ -0,0 +1,16 @@
#!/bin/sh
security create-keychain -p travis build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p travis build.keychain
security set-keychain-settings -t 3600 -l ~/Library/Keychains/build.keychain
security import ./Lib/Certificates/apple.cer -k ~/Library/Keychains/build.keychain -T /usr/bin/codesign
security import ./Lib/Certificates/ios_developer.p12 -k ~/Library/Keychains/build.keychain -P $PASSPHRASE -T /usr/bin/codesign
security import ./Lib/Certificates/developer_id_app.p12 -k ~/Library/Keychains/build.keychain -P $PASSPHRASE -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k travis build.keychain
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp ./Lib/Certificates/*.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
cp ./Lib/Certificates/*.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/

View File

@ -0,0 +1,9 @@
#!/bin/sh
CERT_DIR="./Lib/Certificates"
FILES=('ios_developer.p12' 'developer_id_app.p12' 'iOS_Development.mobileprovision'\
'tvOS_Development.mobileprovision' 'KeychainAccess_Tests.provisionprofile')
for file in ${FILES[@]}; do
openssl aes-256-cbc -k "$ENCRYPTION_SECRET" -in "$CERT_DIR"/"$file".enc -d -a -out "$CERT_DIR"/"$file"
done

View File

@ -0,0 +1,55 @@
//
// AppDelegate.swift
// TestHost
//
// Created by kishikawa katsumi on 7/10/16.
// Copyright © 2016 kishikawa katsumi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(OSX)
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(aNotification: NSNotification) {}
}
#else
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
#if swift(>=4.2)
private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#else
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
#endif
}
#endif

View File

@ -0,0 +1,93 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
<key>NSPrincipalClass</key>
<string>$(PRINCIPAL_CLASS)</string>
</dict>
</plist>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.kishikawakatsumi.KeychainAccess.TestHost</string>
<string>$(AppIdentifierPrefix)shared</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
//
// Package.swift
// KeychainAccess
//
// Created by kishikawa katsumi on 2015/12/4.
// Copyright (c) 2015 kishikawa katsumi. All rights reserved.
//
import PackageDescription
let package = Package(
name: "KeychainAccess"
)

View File

@ -0,0 +1,602 @@
# KeychainAccess
[![CI Status](http://img.shields.io/travis/kishikawakatsumi/KeychainAccess.svg)](https://travis-ci.org/kishikawakatsumi/KeychainAccess)
[![codecov](https://codecov.io/gh/kishikawakatsumi/KeychainAccess/branch/master/graph/badge.svg)](https://codecov.io/gh/kishikawakatsumi/KeychainAccess)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Version](https://img.shields.io/cocoapods/v/KeychainAccess.svg)](http://cocoadocs.org/docsets/KeychainAccess)
[![Platform](https://img.shields.io/cocoapods/p/KeychainAccess.svg)](http://cocoadocs.org/docsets/KeychainAccess)
[![Swift 3.x](https://img.shields.io/badge/Swift-3.x-orange.svg?style=flat)](https://swift.org/)
[![Swift 4.0](https://img.shields.io/badge/Swift-4.0-orange.svg?style=flat)](https://swift.org/)
[![Swift 4.1](https://img.shields.io/badge/Swift-4.1-orange.svg?style=flat)](https://swift.org/)
[![Swift 4.2](https://img.shields.io/badge/Swift-4.2-orange.svg?style=flat)](https://swift.org/)
KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X. Makes using Keychain APIs extremely easy and much more palatable to use in Swift.
<img src="https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/01.png" width="320px" />
<img src="https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/02.png" width="320px" />
<img src="https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/03.png" width="320px" />
## :bulb: Features
- Simple interface
- Support access group
- [Support accessibility](#accessibility)
- [Support iCloud sharing](#icloud_sharing)
- **[Support TouchID and Keychain integration (iOS 8+)](#touch_id_integration)**
- **[Support Shared Web Credentials (iOS 8+)](#shared_web_credentials)**
- [Works on both iOS & OS X](#requirements)
- [watchOS and tvOS are supported](#requirements)
- **[Swift 4 & Swift 3 compatible](#requirements)**
## :book: Usage
##### :eyes: See also:
- [:link: iOS Example Project](https://github.com/kishikawakatsumi/KeychainAccess/tree/master/Examples/Example-iOS)
### :key: Basics
#### Saving Application Password
```swift
let keychain = Keychain(service: "com.example.github-token")
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
#### Saving Internet Password
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
### :key: Instantiation
#### Create Keychain for Application Password
```swift
let keychain = Keychain(service: "com.example.github-token")
```
```swift
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
```
#### Create Keychain for Internet Password
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
```
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https, authenticationType: .htmlForm)
```
### :key: Adding an item
#### subscripting
##### for String
```swift
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
```swift
keychain[string: "kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
##### for NSData
```swift
keychain[data: "secret"] = NSData(contentsOfFile: "secret.bin")
```
#### set method
```swift
keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
```
#### error handling
```swift
do {
try keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
}
catch let error {
print(error)
}
```
### :key: Obtaining an item
#### subscripting
##### for String (If the value is NSData, attempt to convert to String)
```swift
let token = keychain["kishikawakatsumi"]
```
```swift
let token = keychain[string: "kishikawakatsumi"]
```
##### for NSData
```swift
let secretData = keychain[data: "secret"]
```
#### get methods
##### as String
```swift
let token = try? keychain.get("kishikawakatsumi")
```
```swift
let token = try? keychain.getString("kishikawakatsumi")
```
##### as NSData
```swift
let data = try? keychain.getData("kishikawakatsumi")
```
### :key: Removing an item
#### subscripting
```swift
keychain["kishikawakatsumi"] = nil
```
#### remove method
```swift
do {
try keychain.remove("kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
### :key: Set Label and Comment
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
do {
try keychain
.label("github.com (kishikawakatsumi)")
.comment("github access token")
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
### :key: Obtaining Other Attributes
#### PersistentRef
```swift
let keychain = Keychain()
let persistentRef = keychain[attributes: "kishikawakatsumi"].persistentRef
...
```
#### Creation Date
```swift
let keychain = Keychain()
let creationDate = keychain[attributes: "kishikawakatsumi"].creationDate
...
```
#### All Attributes
```swift
let keychain = Keychain()
do {
let attributes = try keychain.get("kishikawakatsumi") { $0 }
print(attributes.comment)
print(attributes.label)
print(attributes.creator)
...
} catch let error {
print("error: \(error)")
}
```
##### subscripting
```swift
let keychain = Keychain()
let attributes = keychain[attributes: "kishikawakatsumi"]
print(attributes.comment)
print(attributes.label)
print(attributes.creator)
```
### :key: Configuration (Accessibility, Sharing, iCloud Sync)
**Provides fluent interfaces**
```swift
let keychain = Keychain(service: "com.example.github-token")
.label("github.com (kishikawakatsumi)")
.synchronizable(true)
.accessibility(.afterFirstUnlock)
```
#### <a name="accessibility"> Accessibility
##### Default accessibility matches background application (=kSecAttrAccessibleAfterFirstUnlock)
```swift
let keychain = Keychain(service: "com.example.github-token")
```
##### For background application
###### Creating instance
```swift
let keychain = Keychain(service: "com.example.github-token")
.accessibility(.afterFirstUnlock)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
###### One-shot
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain
.accessibility(.afterFirstUnlock)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
##### For foreground application
###### Creating instance
```swift
let keychain = Keychain(service: "com.example.github-token")
.accessibility(.whenUnlocked)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
###### One-shot
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain
.accessibility(.whenUnlocked)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
#### :couple: Sharing Keychain items
```swift
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
```
#### <a name="icloud_sharing"> :arrows_counterclockwise: Synchronizing Keychain items with iCloud
###### Creating instance
```swift
let keychain = Keychain(service: "com.example.github-token")
.synchronizable(true)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
```
###### One-shot
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain
.synchronizable(true)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
print("error: \(error)")
}
```
### <a name="touch_id_integration"> :fu: Touch ID integration
**Any Operation that require authentication must be run in the background thread.**
**If you run in the main thread, UI thread will lock for the system to try to display the authentication dialog.**
#### :closed_lock_with_key: Adding a Touch ID protected item
If you want to store the Touch ID protected Keychain item, specify `accessibility` and `authenticationPolicy` attributes.
```swift
let keychain = Keychain(service: "com.example.github-token")
DispatchQueue.global().async {
do {
// Should be the secret invalidated when passcode is removed? If not then use `.WhenUnlocked`
try keychain
.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence)
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
// Error handling if needed...
}
}
```
#### :closed_lock_with_key: Updating a Touch ID protected item
The same way as when adding.
**Do not run in the main thread if there is a possibility that the item you are trying to add already exists, and protected.**
**Because updating protected items requires authentication.**
Additionally, you want to show custom authentication prompt message when updating, specify an `authenticationPrompt` attribute.
If the item not protected, the `authenticationPrompt` parameter just be ignored.
```swift
let keychain = Keychain(service: "com.example.github-token")
DispatchQueue.global().async {
do {
// Should be the secret invalidated when passcode is removed? If not then use `.WhenUnlocked`
try keychain
.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .userPresence)
.authenticationPrompt("Authenticate to update your access token")
.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
} catch let error {
// Error handling if needed...
}
}
```
#### :closed_lock_with_key: Obtaining a Touch ID protected item
The same way as when you get a normal item. It will be displayed automatically Touch ID or passcode authentication If the item you try to get is protected.
If you want to show custom authentication prompt message, specify an `authenticationPrompt` attribute.
If the item not protected, the `authenticationPrompt` parameter just be ignored.
```swift
let keychain = Keychain(service: "com.example.github-token")
DispatchQueue.global().async {
do {
let password = try keychain
.authenticationPrompt("Authenticate to login to server")
.get("kishikawakatsumi")
print("password: \(password)")
} catch let error {
// Error handling if needed...
}
}
```
#### :closed_lock_with_key: Removing a Touch ID protected item
The same way as when you remove a normal item.
There is no way to show Touch ID or passcode authentication when removing Keychain items.
```swift
let keychain = Keychain(service: "com.example.github-token")
do {
try keychain.remove("kishikawakatsumi")
} catch let error {
// Error handling if needed...
}
```
### <a name="shared_web_credentials"> :key: Shared Web Credentials
> Shared web credentials is a programming interface that enables native iOS apps to share credentials with their website counterparts. For example, a user may log in to a website in Safari, entering a user name and password, and save those credentials using the iCloud Keychain. Later, the user may run a native app from the same developer, and instead of the app requiring the user to reenter a user name and password, shared web credentials gives it access to the credentials that were entered earlier in Safari. The user can also create new accounts, update passwords, or delete her account from within the app. These changes are then saved and used by Safari.
<https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/>
```swift
let keychain = Keychain(server: "https://www.kishikawakatsumi.com", protocolType: .HTTPS)
let username = "kishikawakatsumi@mac.com"
// First, check the credential in the app's Keychain
if let password = try? keychain.get(username) {
// If found password in the Keychain,
// then log into the server
} else {
// If not found password in the Keychain,
// try to read from Shared Web Credentials
keychain.getSharedPassword(username) { (password, error) -> () in
if password != nil {
// If found password in the Shared Web Credentials,
// then log into the server
// and save the password to the Keychain
keychain[username] = password
} else {
// If not found password either in the Keychain also Shared Web Credentials,
// prompt for username and password
// Log into server
// If the login is successful,
// save the credentials to both the Keychain and the Shared Web Credentials.
keychain[username] = inputPassword
keychain.setSharedPassword(inputPassword, account: username)
}
}
}
```
#### Request all associated domain's credentials
```swift
Keychain.requestSharedWebCredential { (credentials, error) -> () in
}
```
#### Generate strong random password
Generate strong random password that is in the same format used by Safari autofill (xxx-xxx-xxx-xxx).
```swift
let password = Keychain.generatePassword() // => Nhu-GKm-s3n-pMx
```
#### How to set up Shared Web Credentials
> 1. Add a com.apple.developer.associated-domains entitlement to your app. This entitlement must include all the domains with which you want to share credentials.
> 2. Add an apple-app-site-association file to your website. This file must include application identifiers for all the apps with which the site wants to share credentials, and it must be properly signed.
> 3. When the app is installed, the system downloads and verifies the site association file for each of its associated domains. If the verification is successful, the app is associated with the domain.
**More details:**
<https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/>
### :key: Debugging
#### Display all stored items if print keychain object
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
print("\(keychain)")
```
```
=>
[
[authenticationType: default, key: kishikawakatsumi, server: github.com, class: internetPassword, protocol: https]
[authenticationType: default, key: hirohamada, server: github.com, class: internetPassword, protocol: https]
[authenticationType: default, key: honeylemon, server: github.com, class: internetPassword, protocol: https]
]
```
#### Obtaining all stored keys
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
let keys = keychain.allKeys()
for key in keys {
print("key: \(key)")
}
```
```
=>
key: kishikawakatsumi
key: hirohamada
key: honeylemon
```
#### Obtaining all stored items
```swift
let keychain = Keychain(server: "https://github.com", protocolType: .https)
let items = keychain.allItems()
for item in items {
print("item: \(item)")
}
```
```
=>
item: [authenticationType: Default, key: kishikawakatsumi, server: github.com, class: InternetPassword, protocol: https]
item: [authenticationType: Default, key: hirohamada, server: github.com, class: InternetPassword, protocol: https]
item: [authenticationType: Default, key: honeylemon, server: github.com, class: InternetPassword, protocol: https]
```
## Requirements
| | OS | Swift |
|------------|----------------------------------------|---------------|
| **v1.1.x** | iOS 7+, OSX 10.9+ | 1.1 |
| **v1.2.x** | iOS 7+, OSX 10.9+ | 1.2 |
| **v2.0.x** | iOS 7+, OSX 10.9+, watchOS 2+ | 2.0 |
| **v2.1.x** | iOS 7+, OSX 10.9+, watchOS 2+ | 2.0 |
| **v2.2.x** | iOS 8+, OSX 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1 |
| **v2.3.x** | iOS 8+, OSX 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1, 2.2 |
| **v2.4.x** | iOS 8+, OSX 10.9+, watchOS 2+, tvOS 9+ | 2.2, 2.3 |
| **v3.0.x** | iOS 8+, OSX 10.9+, watchOS 2+, tvOS 9+ | 3.x |
| **v3.1.x** | iOS 8+, OSX 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2 |
## Installation
### CocoaPods
KeychainAccess is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following lines to your Podfile:
```ruby
use_frameworks!
pod 'KeychainAccess'
```
### Carthage
KeychainAccess is available through [Carthage](https://github.com/Carthage/Carthage). To install
it, simply add the following line to your Cartfile:
`github "kishikawakatsumi/KeychainAccess"`
### Swift Package Manager
KeychainAccess is also available through [Swift Package Manager](https://github.com/apple/swift-package-manager/).
First, create `Package.swift` that its package declaration includes:
```swift
import PackageDescription
let package = Package(
dependencies: [
.Package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", majorVersion: 2)
]
)
```
Then, type
```shell
$ swift build
```
### To manually add to your project
1. Add `Lib/KeychainAccess.xcodeproj` to your project
2. Link `KeychainAccess.framework` with your target
3. Add `Copy Files Build Phase` to include the framework to your application bundle
_See [iOS Example Project](https://github.com/kishikawakatsumi/KeychainAccess/tree/master/Examples/Example-iOS) as reference._
<img src="https://raw.githubusercontent.com/kishikawakatsumi/KeychainAccess/master/Screenshots/Installation.png" width="800px" />
## Author
kishikawa katsumi, kishikawakatsumi@mac.com
## License
KeychainAccess is available under the MIT license. See the LICENSE file for more info.

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

View File

@ -0,0 +1 @@
../Lib/KeychainAccess/Keychain.swift

View File

@ -12,6 +12,8 @@
F3D3F32A2215A3A500628D44 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F3D3F3282215A3A500628D44 /* Main.storyboard */; };
F3D3F32C2215A3A600628D44 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F3D3F32B2215A3A600628D44 /* Assets.xcassets */; };
F3D3F32F2215A3A600628D44 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F3D3F32D2215A3A600628D44 /* LaunchScreen.storyboard */; };
F3D3F3372215C35800628D44 /* Cartfile in Resources */ = {isa = PBXBuildFile; fileRef = F3D3F3362215C35800628D44 /* Cartfile */; };
F3D3F38A22164C6000628D44 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3D3F38922164C6000628D44 /* KeychainAccess.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -22,6 +24,8 @@
F3D3F32B2215A3A600628D44 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
F3D3F32E2215A3A600628D44 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
F3D3F3302215A3A600628D44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F3D3F3362215C35800628D44 /* Cartfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cartfile; sourceTree = "<group>"; };
F3D3F38922164C6000628D44 /* KeychainAccess.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = KeychainAccess.framework; path = Carthage/Build/iOS/KeychainAccess.framework; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -29,6 +33,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F3D3F38A22164C6000628D44 /* KeychainAccess.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -40,6 +45,8 @@
children = (
F3D3F3232215A3A500628D44 /* Secret Swift */,
F3D3F3222215A3A500628D44 /* Products */,
F3D3F3362215C35800628D44 /* Cartfile */,
F3D3F3862215C93A00628D44 /* Frameworks */,
);
sourceTree = "<group>";
};
@ -64,6 +71,14 @@
path = "Secret Swift";
sourceTree = "<group>";
};
F3D3F3862215C93A00628D44 /* Frameworks */ = {
isa = PBXGroup;
children = (
F3D3F38922164C6000628D44 /* KeychainAccess.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -74,6 +89,7 @@
F3D3F31D2215A3A500628D44 /* Sources */,
F3D3F31E2215A3A500628D44 /* Frameworks */,
F3D3F31F2215A3A500628D44 /* Resources */,
F3D3F3852215C70E00628D44 /* ShellScript */,
);
buildRules = (
);
@ -124,12 +140,35 @@
files = (
F3D3F32F2215A3A600628D44 /* LaunchScreen.storyboard in Resources */,
F3D3F32C2215A3A600628D44 /* Assets.xcassets in Resources */,
F3D3F3372215C35800628D44 /* Cartfile in Resources */,
F3D3F32A2215A3A500628D44 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
F3D3F3852215C70E00628D44 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/Carthage/Build/iOS/KeychainAccess.framework",
);
outputFileListPaths = (
);
outputPaths = (
"$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/KeychainAccess.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n/usr/local/bin/carthage copy-frameworks\n\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
F3D3F31D2215A3A500628D44 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -284,6 +323,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = QRXXH2RKAG;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = "Secret Swift/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -302,6 +345,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = QRXXH2RKAG;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = "Secret Swift/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",

View File

@ -10,7 +10,7 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Home View Controller-->
<!--✌️ Swift Notes-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="HomeViewController" customModule="Secret_Swift" customModuleProvider="target" sceneMemberID="viewController">
@ -19,18 +19,14 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="meP-dq-KlX">
<rect key="frame" x="115.5" y="309.5" width="144" height="48"/>
<constraints>
<constraint firstAttribute="width" constant="144" id="PJn-GK-Ry8"/>
<constraint firstAttribute="height" constant="48" id="pvs-9I-1H5"/>
</constraints>
<rect key="frame" x="116" y="310" width="143" height="47"/>
<state key="normal" title="🔐 Authenticate"/>
<connections>
<action selector="authenticateTapped:" destination="BYZ-38-t0r" eventType="touchUpInside" id="SJF-y4-DNe"/>
</connections>
</button>
<textView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="tdi-a4-0ZX">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
@ -38,18 +34,20 @@
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="tdi-a4-0ZX" secondAttribute="trailing" id="0Vo-K6-29X"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="BDU-pn-ii6"/>
<constraint firstItem="meP-dq-KlX" firstAttribute="centerX" secondItem="tdi-a4-0ZX" secondAttribute="centerX" id="IKc-MW-f1h"/>
<constraint firstItem="meP-dq-KlX" firstAttribute="centerY" secondItem="tdi-a4-0ZX" secondAttribute="centerY" id="UfS-NL-YHN"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="uUs-Vs-YSw"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="xCf-bc-Nl1"/>
<constraint firstItem="meP-dq-KlX" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="AoE-LM-Dgv"/>
<constraint firstItem="meP-dq-KlX" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="116" id="Jsh-IU-IdS"/>
<constraint firstItem="meP-dq-KlX" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="246" id="PCR-qz-OQW"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="SOR-d6-Tt1"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="duq-RF-FFW"/>
<constraint firstAttribute="trailing" secondItem="tdi-a4-0ZX" secondAttribute="trailing" id="kIF-PF-iNl"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="centerX" secondItem="meP-dq-KlX" secondAttribute="centerX" id="sqG-He-qhH"/>
<constraint firstItem="tdi-a4-0ZX" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="w5E-Ga-Ijq"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
<navigationItem key="navigationItem" id="vNj-0T-KPw"/>
<navigationItem key="navigationItem" title="✌️ Swift Notes" id="vNj-0T-KPw"/>
<connections>
<outlet property="textView" destination="tdi-a4-0ZX" id="TPP-ul-xHr"/>
<outlet property="secretTextView" destination="tdi-a4-0ZX" id="TPP-ul-xHr"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>

View File

@ -7,9 +7,21 @@
//
import UIKit
import KeychainAccess
import LocalAuthentication
enum Title: String {
case nondescript = "✌️ Swift Notes"
case unlocked = "🔓 Secret Unlocked"
}
enum ViewMode: String {
case secretHidden
case secretShowing
}
class HomeViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var secretTextView: UITextView!
lazy var notificationCenter = NotificationCenter.default
@ -18,21 +30,51 @@ class HomeViewController: UIViewController {
UIResponder.keyboardWillChangeFrameNotification,
]
lazy var keychain = Keychain(service: "io.sipple.Secret-Swift")
lazy var authContext = LAContext()
var currentViewMode = ViewMode.secretHidden {
didSet {
viewModeChanged()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addNotificationObservers()
}
func addNotificationObservers() {
for notification in keyboardMovementNotifications {
notificationCenter.addObserver(self, selector: #selector(handleKeyboardMovement), name: notification, object: nil)
}
notificationCenter.addObserver(
self, selector: #selector(saveSecretMessage), name: UIApplication.willResignActiveNotification, object: nil
)
}
func unlockSecretMessage() {
currentViewMode = .secretShowing
if let secretText = try? keychain.getString("secretText") {
secretTextView.text = secretText
}
}
@objc func saveSecretMessage() {
guard currentViewMode == .secretShowing else { return }
keychain[string: "secretText"] = secretTextView.text
// have the text view give up focus so the keyboard will hide
secretTextView.resignFirstResponder()
currentViewMode = .secretHidden
}
@objc func handleKeyboardMovement(notification: Notification) {
guard let userInfo = notification.userInfo else { return }
@ -40,17 +82,66 @@ class HomeViewController: UIViewController {
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
if notification.name == UIResponder.keyboardWillHideNotification {
textView.contentInset = UIEdgeInsets.zero
secretTextView.contentInset = UIEdgeInsets.zero
} else {
textView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
secretTextView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
}
textView.scrollIndicatorInsets = textView.contentInset
textView.scrollRangeToVisible(textView.selectedRange)
secretTextView.scrollIndicatorInsets = secretTextView.contentInset
secretTextView.scrollRangeToVisible(secretTextView.selectedRange)
}
func viewModeChanged() {
switch currentViewMode {
case .secretHidden:
title = Title.nondescript.rawValue
secretTextView.isHidden = true
case .secretShowing:
title = Title.unlocked.rawValue
secretTextView.isHidden = false
}
}
func authFailed() {
let alertController = UIAlertController(
title: "Authentication Failed",
message: "You could not be verified. Please try again",
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "OK", style: .default))
present(alertController, animated: true)
}
@IBAction func authenticateTapped(_ sender: Any) {
var error: NSError?
if authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
authContext.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: reason,
reply: { (success: Bool, error: Error?) in
DispatchQueue.main.async { [unowned self] in
if success {
self.unlockSecretMessage()
} else {
self.authFailed()
}
}
}
)
} else {
// 📝 TODO: Handle case where no biometrics are supported
print("No Bio")
}
}
}

View File

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSFaceIDUsageDescription</key>
<string>Identify yourself!</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>

View File

@ -44,7 +44,7 @@
| 25 | 📱<br>[Photo Share](/25-photo-share) | MultipeerConnectivity, MCSession, MCBrowswerViewController, showConnectionPrompt(), MCPeerID, MCAdvertiserAssistant, MCSessionDelegate, MCBrowserViewControllerDelegate, MCSession.send | ✅ |
| 26 | 🎮<br>[Marble Maze](/26-marble-maze) | categoryBitMask, collisionBitMask, contactTestBitMask, CMMotionManager, startAccelerometerUpdates, reading accelerometer data, compiler directives | ✅ |
| 27 | 🛠<br>[Core Graphics](/27-core-graphics) | Core 👏 Graphics 👏, UIGraphicsImageRenderer, exporting images with UIGraphicsImageRenderer.image(), UIGraphicsImageRendererContext, CGContext, CGContext.addRect(), CGContext.addEllipse(), NSString.draw(with:), UIFont, NSMutableParagraphStyle(), drawing UIImages straight into a rendering context | ✅ |
| 28 | 📱<br>[Secret Swift](/28-secret-swift) | KeychainWrapper, resignFirstResponder(), NotificationCenter, UIApplication.willResignActiveNotification, LocalAuthentication, LAContext, canEvaluatePolicy(), .deviceOwnerAuthenticationWithBiometrics, evaluatePolicy(), `[unowned self]`, `self`, Privacy for Touch ID & Face ID | 🔴 |
| 28 | 📱<br>[Secret Swift](/28-secret-text-editor) | Using the KeychainAccess library, resignFirstResponder(), NotificationCenter, UIApplication.willResignActiveNotification, LocalAuthentication, LAContext, canEvaluatePolicy(), .deviceOwnerAuthenticationWithBiometrics, evaluatePolicy(), privacy for Touch ID & Face ID, simulating Face ID with the Simulator | ✅ |
| 29 | 🎮<br>[Exploding Monkeys](/29-exploding-monkeys) | UIKit + SpriteKit, Texture Atlases, Scene Transitions, Destructable Terrain | 🔴 |
| 30 | 🛠<br>[Instruments](/30-instruments) | TimeProfiler, Color Blended Layers, Color Offscreen-Rendered Yellow, Color Hits Green and Misses Red | 🔴 |