• Stars
    star
    470
  • Rank 89,862 (Top 2 %)
  • Language
    Swift
  • License
    MIT License
  • Created about 4 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Helps you define secure storages for your properties using Swift property wrappers.

๐Ÿ” Secure Property Storage

Helps you define secure storages for your properties using Swift property wrappers.

Twitter Swift License Swift Package Manager Carthage Bitrise Quality Maintainability Coverage Documentation

๐ŸŒŸ Features

All keys are hashed using SHA512 and all values are encrypted using AES-GCM to keep user information safe, automagically. Symmetric key is stored in Keychain in a totally secure way.

๐Ÿ’ Basic usage

@UserDefault

This property wrapper will store your property in UserDefaults using StoreKey (any String but i recommend you a String typed enum). Optionally, you can assign a default value to the property that will be secure stored at initialization.

@UserDefault(<#StoreKey#>)
var yourProperty: YourType? = yourDefaultValueIfNeeded

UserDefaultsStorage is also available, a subclass of UserDefaults with all the security provided by this library, where you can customize suite name.

@Keychain

This property wrapper will store your property in Keychain using StoreKey.

@Keychain(<#StoreKey#>)
var yourProperty: YourType? = yourDefaultValueIfNeeded

As UserDefaultsStorage, KeychainStorage is also available, where you can customize access, group and synchronize it with iCloud.

@Singleton

This property wrapper will store your property in a memory singleton, every property with the same wrapper and key can access or modify the value from wherever it is.

@Singleton(<#StoreKey#>)
var yourProperty: YourType? = yourDefaultValueIfNeeded

As KeychainStorage, SingletonStorage is also available.

@Inject

This property wrapper is similar to @Singleton but, together with @Register, will inject your dependencies. More details in Dependency Injection usage guide.

@Inject
var yourDependency: YourProtocol?

As SingletonStorage, InjectStorage is also available.

@Store

This is a custom wrapper, you can define your own Storage protocol implementation.

@Store(<#YourStorage#>, <#StoreKey#>)
var yourProperty: YourType? = yourDefaultValueIfNeeded

As InjectStorage, DelegatedStorage is also available with all the magic of this library.

๐Ÿง™โ€โ™‚๏ธ Codable usage

If your property conforms Codable protocol, just add Codable keyword as prefix of your property wrapper.

  • @CodableUserDefault
  • @CodableKeychain
  • @CodableSingleton
  • @CodableStore

๐Ÿฅก Unwrapped usage

To avoid continually unwrapping your property, just add Unwrapped keyword as prefix of your property wrapper, assign a default value (mandatory except for @UnwrappedInject), and it will return stored value or default value, but your property will always be there for you.

  • @UnwrappedUserDefault
  • @UnwrappedKeychain
  • @UnwrappedSingleton
  • @UnwrappedInject
  • @UnwrappedStore

๐Ÿฅก + ๐Ÿง™โ€โ™‚๏ธ Combo usage

You can also combine previous cases in case you need it, unwrapped first please.

  • @UnwrappedCodableUserDefault
  • @UnwrappedCodableKeychain
  • @UnwrappedCodableSingleton
  • @UnwrappedCodableStore

๐Ÿ’‰ Dependency Injection usage

@Register (click to expand)

This property wrapper will register the implementations of your dependencies. Register them wherever you want before inject it, but be sure to do it only once (except if you use qualifiers), for example, in an Injector class. You can register through a protocol or directly using your class implementation.

@Register
var yourDependency: YourProtocol = YourImplementation()

@Register
var yourDependency = YourImplementation()

You can also define a closure that builds your dependency. Just remember cast your dependency if you are going to inject it through a protocol.

@Register
var yourDependency = {
    YourImplementation() as YourProtocol
}

@Register
var yourDependency = {
    YourImplementation()
}

You can also register your dependencies only after the moment someone tries to inject them and you haven't registered them yet, for this you can use the error closure.

InjectStorage.standard.errorClosure = { error in
    if case InjectError.notFound = error {
        YourImplementation.register()
    }
}

You can get this syntactic sugar because you can now use property wrappers in function parameters.

static func register(@Register yourDependency: YourProtocol = YourImplementation()) {}
@Inject and @UnwrappedInject (click to expand)

These property wrappers injects your dependencies @Register implementations.

@Inject
var yourDependency: YourProtocol?

@Inject
var yourDependency: YourImplementation?

@UnwrappedInject
var yourUnwrappedDependency: YourProtocol

@UnwrappedInject
var yourUnwrappedDependency: YourImplementation

Scope

Because these property wrappers works similarly to @Singleton, the default scope is .singleton, but if you use builder closures on @Register, you can modify them to inject a single instance.

@Inject(.instance)
var yourDependency: YourProtocol?

@UnwrappedInject(.instance)
var yourUnwrappedDependency: YourProtocol
@InjectWith and @UnwrappedInjectWith (click to expand)

Your dependency may need parameters when injecting, you can pass them with these property wrappers. Simply define a model with your dependency parameters and pass it. It will inject a new instance built with these parameters.

@Register
var yourDependency = { parameters in
    YourImplementation(parameters) as YourProtocol
}

@Inject(YourParameters())
var yourDependency: YourProtocol?

@UnwrappedInject(YourParameters())
var yourUnwrappedDependency: YourProtocol
Qualifiers (click to expand)

You can use qualifiers to provide various implementations of a particular dependency. A qualifier is just a @objc protocol that you apply to a class.

For example, you could declare Dog and Cat qualifier protocols and apply it to another class that conforms Animal protocol. To declare this qualifier, use the following code:

protocol Animal {
  func sound()
}

@objc protocol Dog {}

@objc protocol Cat {}

You can then define multiple classes that conforms Animal protocol and uses this qualifiers:

class DogImplementation: Animal, Dog {
    func sound() { print("Woof!") }
}

class CatImplementation: Animal, Cat {
    func sound() { print("Meow!") }
}

Both implementations of the class can now be @Register:

@Register
var registerDog: Animal = DogImplementation()

@Register
var registerCat: Animal = CatImplementation()

To inject one or the other implementation, simply add the qualifier(s) to your @Inject:

@UnwrappedInject(Dog.self)
var dog: Animal

@UnwrappedInject(Cat.self)
var cat: Animal

dog.sound() // prints Woof!
cat.sound() // prints Meow!
Testing (click to expand)

One of the advantages of dependency injection is that the code can be easily testable with mock implementation. That is why there is a Mock qualifier that has priority over all, so you can have your dependencies defined in the app and create your mock in the test target simply by adding this qualifier.

// App target

class YourImplementation: YourProtocol {}

@Register
var yourDependency: YourProtocol = YourImplementation()

@Inject
var yourDependency: YourProtocol?
// Test target

class YourMock: YourProtocol, Mock {}

@Register
var yourDependency: YourProtocol = YourMock()
Groups (click to expand)

When you have a lot of dependencies in your app, you may want to optimize dependency resolution.

You can group them using @Register(group:) and a DependencyGroupKey:

@Register(group: <#DependencyGroupKey#>)
var yourDependency: YourProtocol = YourImplementation()

@Inject(group:) will look for those dependencies only in that group:

@Inject(group: <#DependencyGroupKey#>)
var yourDependency: YourProtocol?

๐Ÿ‘€ Examples

Talk is cheap. Show me the code.

    // Securely stored in UserDefaults.
    @UserDefault("username")
    var username: String?

    // Securely stored in Keychain.
    @Keychain("password")
    var password: String?

    // Securely stored in a Singleton storage.
    @Singleton("sessionToken")
    var sessionToken: String?

    // Securely stored in a Singleton storage.
    // Always has a value, the stored or the default.
    @UnwrappedSingleton("refreshToken")
    var refreshToken: String = "B0610306-A33F"

    struct User: Codable {
        let username: String
        let password: String?
        let sessionToken: String?
    }

    // Codable model securely stored in UserDefaults.
    @CodableUserDefault("user")
    var user: User?

๐Ÿ›  Compatibility

  • macOS 10.15+
  • iOS 13.0+
  • iPadOS 13.0+
  • tvOS 13.0+
  • watchOS 6.0+

โš™๏ธ Installation

You can use the Swift Package Manager by declaring SecurePropertyStorage as a dependency in your Package.swift file:

.package(url: "https://github.com/alexruperez/SecurePropertyStorage", from: "0.7.1")

By default, all property wrappers are installed and you can import them, but if you want, you can install only some of them:

  • UserDefault: @*UserDefault property wrappers.
  • Keychain: @*Keychain property wrappers.
  • Singleton: @*Singleton property wrappers.
  • Storage: @*Store property wrappers.
  • Inject: @*Inject property wrappers.

For more information, see the Swift Package Manager documentation.

Or you can use Carthage:

github "alexruperez/SecurePropertyStorage"

๐Ÿป Etc.

  • Featured in Dave Verwer's iOS Dev Weekly - Issue 450, thanks Dave!
  • Contributions are very welcome. Thanks Alberto Garcia and Chen!
  • Attribution is appreciated (let's spread the word!), but not mandatory.

๐Ÿ‘จโ€๐Ÿ’ป Author

Alex Rupรฉrez โ€“ @alexruperez โ€“ [email protected]

๐Ÿ‘ฎโ€โ™‚๏ธ License

SecurePropertyStorage is available under the MIT license. See the LICENSE file for more info.

More Repositories

1

UIUserNotificationSettings-Extension

Helper methods that will make you much easier to handle #Interactive #Notifications.
Objective-C
272
star
2

ARAutocompleteTextView

ARAutocompleteTextView is a subclass of UITextView that automatically displays text suggestions in real-time. This is perfect for automatically suggesting the domain as a user types an email address, #hashtag or @alexruperez.
Objective-C
262
star
3

LaunchScreenSnapshot

Protects sensitive data in your app snapshot.
Swift
206
star
4

SpeechRecognizerButton

UIButton subclass with push to talk recording, speech recognition and Siri-style waveform view.
Swift
163
star
5

UILabel-AutomaticWriting

UILabel category with automatic writing (type out) animation.
Objective-C
158
star
6

Tagging

๐Ÿท Type-safe tags in Swift
Swift
91
star
7

ARHomeScreenShortcuts

Installs home screen shortcuts to features of your app.
Objective-C
79
star
8

ARDetector

CIDetector, AVCaptureVideoDataOutput and AVCaptureMetadataOutput categories. With face, rectangle, QR Code and TEXT CIDetector and blocks for AVCaptureOutput handling.
Objective-C
71
star
9

ARSafariActivity

A UIActivity subclass that opens URLs in Safari
Objective-C
55
star
10

NSDate-Extension

Use NSDate-Extension to handle NSDate objects easily. Syntactic sugar. #DSL Style
Objective-C
48
star
11

StateMachine

State machine creation framework written in Swift inspired by GKStateMachine from Apple GameplayKit
Swift
48
star
12

FSNetworkingSearchController

Search controller with suggest completion using Foursquare API following Instagram design.
Objective-C
46
star
13

ARWebServerActivity

A UIActivity subclass that share files via GCDWebServer with Twitter Bootstrap UI.
Objective-C
40
star
14

AVPlayerItemHomeOutput

Coordinate the output of content associated with your HomeKit lightbulbs. #Ambilight
Swift
37
star
15

ARObjectCollectionViewController

UIViewController that can present a JSON NSString, JSON NSData, JSON URL, XML NSData, XML URL, RSS NSData, RSS URL, NSDictionary, NSArray, NSSet, UIImage EXIF Metadata...
Objective-C
34
star
16

PFLinkedInUtils

The #PFLinkedInUtils class provides utility functions for working with #LinkedIn in a #Parse application.
Objective-C
31
star
17

ARDeepLinkButton

#UIButton subclass that handle deep links, shows in-app #SKStoreProductViewController or redirects to the #AppStore. Written in #Swift 2.1.1
Swift
26
star
18

ARSpeechActivity

ARSpeechActivity is a UIActivity subclass that uses AVSpeechUtterance to read aloud the shared NSString
Objective-C
25
star
19

ARAutocompleteSearchBar

ARAutocompleteSearchBar is a subclass of UISearchBar that automatically displays text suggestions in real-time.
Objective-C
23
star
20

ARFacebookShareKitActivity

Launch FBSDKShareKit from UIActivityViewController instead of the default Facebook share sheet.
Objective-C
23
star
21

MADBike

This is the public repository of the MADBike app for iOS. Public bike rental service for BiciMAD.
Objective-C
23
star
22

ARAlertController

UIAlertController compatible iOS >= 5.0
Objective-C
22
star
23

SafeBrowsing

Protect your users against malware and phishing threats using Google Safe Browsing
Swift
20
star
24

iOS-Coding-Best-Practices

iOS Coding Best Practices
Objective-C
16
star
25

NSDictionary-Verified

NSDictionary+Verified checks NSNull (aka kCFNull) objects and it changes to nil
Objective-C
11
star
26

OpenMarvel

Open source iOS application for searching Marvel characters.
Swift
5
star
27

ARButtonBlock

UIButton subclass with touchUpInside as block helper.
Objective-C
4
star
28

ImageFromWebView

Captures an image of a UIWebView, makes an UIImage, shows on an UIImageView and saves it into the gallery.
Objective-C
4
star
29

swift-library-template

Swift Library Template, just run ./generate.sh
Swift
3
star
30

Tasks

Very useful and complete tutorial explaining how to integrate SiriKit in your apps.
Swift
3
star
31

ARFontsMobileconfigGenerator

Ruby script that generates a mobileconfig file for each folder with fonts that can be installed on any iOS / OS X and use those fonts in apps like Pages, Numbers, Keynote...
Ruby
3
star
32

swift-executable-template

Swift Executable Template, just run ./generate.sh
Swift
2
star
33

Coverflow

Coverflow Implementation using PSTCollectionView (iOS5 supported UICollectionView)
Objective-C
1
star
34

CryptoKitCLI

Take Apple CryptoKit to the command line and perform cryptographic operations securely and efficiently.
Swift
1
star
35

alexruperez-android-app

This is a very simple app, that uses a webview to display http://alexruperez.com on your Android device.
Java
1
star
36

ARFormTextField

UITextField subclass with doneBlock and nextTextField helpers for easier forms creation
Objective-C
1
star