Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added obfuscation for keys #67

Merged
merged 7 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

##### Enhancements

* Added obfuscation for keys/passwords to ensure that they don't appear in plaintext.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor, maybe just mention the "Obfuscation" subspec and the ObfuscatedKey class so that clients can get a general sense of how they can make use of this new feature when they see these release notes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

[Russell Mirabelli](https://github.com/rmirabelli)
[#67](https://github.com/BottleRocketStudios/iOS-UtiliKit/pull/67)

* Updated initial/named view controller example so that the buttons are horizontally centered in the stack view.
[Tyler Milner](https://github.com/tylermilner)
[#65](https://github.com/BottleRocketStudios/iOS-UtiliKit/pull/65)
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ UtiliKit
This library provides several useful and often common additions for iOS applications. These extensions, protocols, and structs are designed to simplify boilerplate code as well as remove common "Stringly-typed" use cases.

### Key Concepts
This library is divided into 5 parts.
This library is divided into 6 parts.
* Instantiation - This subspec changes "Stringly-typed" view instantiation, view controller instantiation, and reusable view dequeuing into type-safe function calls.
* General - This subspec includes extensions for both FileManager and UIView. These simplify getting common URLs and programmatically adding views down to simple variables and function calls.
* Version - This subspec simplifies the display of version and build numbers.
* TimelessDate - This subspec is an abstraction away from Date and Calendar. It is primarily designed to be used for simple scheduling and day comparisons in which the time is less important that the actual day.
* Container - This subspec provides a simple ContainerViewController without any built-in navigation construct.
* Obfuscation - This subspec provides simple routines to remove plaintext passwords or keys from your source code.

### Usage
#### Reusable Views
Expand Down Expand Up @@ -226,6 +227,14 @@ When initializing `ActiveLabel` in Storyboards or Xibs you must set the labels t

When using `ActiveLabel` for snapshot tests you can center the gradient by calling `configureForSnapshotTest()` on your label.

#### ObfuscatedKey

To use an obfuscated key in your code, create one and use the builder variables to encode your key.

``` swift
let key = ObfuscatedKey().T.h.i.s.underscore.I.s.dash.o.b.f.u.s.c.a.t.e.d.value
```

### Example

To run the example project, clone the repo, and run `pod install` from the Example directory first.
Expand Down
6 changes: 6 additions & 0 deletions Sources/UtiliKit/ActiveLabel/ActiveLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import UIKit
/// - Note: `ActiveLabel` loading indicators do not scale with Dynamic Type at this time. The text in the label does scale as expected.
@IBDesignable
class ActiveLabel: UILabel {

// codebeat:disable[TOO_MANY_FUNCTIONS]

static let loadingGray: UIColor = UIColor(red: 233.0/255.0, green: 231.0/255.0, blue: 237.0/255.0, alpha: 1.0)

/// Struct used to represent how an `ActiveLabel` should be displayed. Should be passed into the `ActiveLabel` convenience initializer.
Expand Down Expand Up @@ -382,4 +385,7 @@ private extension ActiveLabel {

return animation
}

// codebeat:enable[TOO_MANY_FUNCTIONS]

}
109 changes: 109 additions & 0 deletions Sources/UtiliKit/Obfuscation/ObfuscatedKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// ObfuscatedKey.swift
// UtiliKit-iOS
//
// Created by Russell Mirabelli on 7/23/19.
// Copyright © 2019 Bottle Rocket Studios. All rights reserved.
//

// Inspired by https://github.com/onmyway133/Arcane/blob/master/Sources/Arcane/Obfuscator.swift

import Foundation

/// One should never commit keys directly into one's source; this is an unsafe practice.
/// When it is impossible to avoid doing so, the key should at least be obfuscated.
/// By using the ObfuscatedKey struct, you can build a human-readable key that nonetheless
/// will not appear simply by running "strings" against your compiled code, and will even
/// not appear as a string within your source code.
public struct ObfuscatedKey {
private let _value: String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we lose the internal variable and use public private(set) value: String ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not available on a "let"; I believe that the immutability of a "let" is important to make the general builder technique make sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point - withdrawn.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't help but feel like I'm missing something here - what does the private let _value: String and public var value { return _value } get us here over a single immutable public let value. As far as I can tell, we aren't mutating it or validating internally and the same-file extensions should have the same access regardless.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. Since my merge is still blocked by the license (ugh), I'll think about this and see if there is a good reason I can find.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed, changed.


public init() {
self._value = ""
}

public init(_ value: String) {
self._value = value
}

public var value: String {
return _value
}
}

public extension ObfuscatedKey {
// codebeat:disable[TOO_MANY_FUNCTIONS]
var A: ObfuscatedKey { return ObfuscatedKey(_value + "A") }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to throw these into a public extension to alleviate the need to define each of these as public var ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice way to avoid all the publics. Done, and thanks!

var B: ObfuscatedKey { return ObfuscatedKey(_value + "B") }
var C: ObfuscatedKey { return ObfuscatedKey(_value + "C") }
var D: ObfuscatedKey { return ObfuscatedKey(_value + "D") }
var E: ObfuscatedKey { return ObfuscatedKey(_value + "E") }
var F: ObfuscatedKey { return ObfuscatedKey(_value + "F") }
var G: ObfuscatedKey { return ObfuscatedKey(_value + "G") }
var H: ObfuscatedKey { return ObfuscatedKey(_value + "H") }
var I: ObfuscatedKey { return ObfuscatedKey(_value + "I") }
var J: ObfuscatedKey { return ObfuscatedKey(_value + "J") }
var K: ObfuscatedKey { return ObfuscatedKey(_value + "K") }
var L: ObfuscatedKey { return ObfuscatedKey(_value + "L") }
var M: ObfuscatedKey { return ObfuscatedKey(_value + "M") }
var N: ObfuscatedKey { return ObfuscatedKey(_value + "N") }
var O: ObfuscatedKey { return ObfuscatedKey(_value + "O") }
var P: ObfuscatedKey { return ObfuscatedKey(_value + "P") }
var Q: ObfuscatedKey { return ObfuscatedKey(_value + "Q") }
var R: ObfuscatedKey { return ObfuscatedKey(_value + "R") }
var S: ObfuscatedKey { return ObfuscatedKey(_value + "S") }
var T: ObfuscatedKey { return ObfuscatedKey(_value + "T") }
var U: ObfuscatedKey { return ObfuscatedKey(_value + "U") }
var V: ObfuscatedKey { return ObfuscatedKey(_value + "V") }
var W: ObfuscatedKey { return ObfuscatedKey(_value + "W") }
var X: ObfuscatedKey { return ObfuscatedKey(_value + "X") }
var Y: ObfuscatedKey { return ObfuscatedKey(_value + "Y") }
var Z: ObfuscatedKey { return ObfuscatedKey(_value + "Z") }

var a: ObfuscatedKey { return ObfuscatedKey(_value + "a") }
var b: ObfuscatedKey { return ObfuscatedKey(_value + "b") }
var c: ObfuscatedKey { return ObfuscatedKey(_value + "c") }
var d: ObfuscatedKey { return ObfuscatedKey(_value + "d") }
var e: ObfuscatedKey { return ObfuscatedKey(_value + "e") }
var f: ObfuscatedKey { return ObfuscatedKey(_value + "f") }
var g: ObfuscatedKey { return ObfuscatedKey(_value + "g") }
var h: ObfuscatedKey { return ObfuscatedKey(_value + "h") }
var i: ObfuscatedKey { return ObfuscatedKey(_value + "i") }
var j: ObfuscatedKey { return ObfuscatedKey(_value + "j") }
var k: ObfuscatedKey { return ObfuscatedKey(_value + "k") }
var l: ObfuscatedKey { return ObfuscatedKey(_value + "l") }
var m: ObfuscatedKey { return ObfuscatedKey(_value + "m") }
var n: ObfuscatedKey { return ObfuscatedKey(_value + "n") }
var o: ObfuscatedKey { return ObfuscatedKey(_value + "o") }
var p: ObfuscatedKey { return ObfuscatedKey(_value + "p") }
var q: ObfuscatedKey { return ObfuscatedKey(_value + "q") }
var r: ObfuscatedKey { return ObfuscatedKey(_value + "r") }
var s: ObfuscatedKey { return ObfuscatedKey(_value + "s") }
var t: ObfuscatedKey { return ObfuscatedKey(_value + "t") }
var u: ObfuscatedKey { return ObfuscatedKey(_value + "u") }
var v: ObfuscatedKey { return ObfuscatedKey(_value + "v") }
var w: ObfuscatedKey { return ObfuscatedKey(_value + "w") }
var x: ObfuscatedKey { return ObfuscatedKey(_value + "x") }
var y: ObfuscatedKey { return ObfuscatedKey(_value + "y") }
var z: ObfuscatedKey { return ObfuscatedKey(_value + "z") }

var n0: ObfuscatedKey { return ObfuscatedKey(_value + "0") }
var n1: ObfuscatedKey { return ObfuscatedKey(_value + "1") }
var n2: ObfuscatedKey { return ObfuscatedKey(_value + "2") }
var n3: ObfuscatedKey { return ObfuscatedKey(_value + "3") }
var n4: ObfuscatedKey { return ObfuscatedKey(_value + "4") }
var n5: ObfuscatedKey { return ObfuscatedKey(_value + "5") }
var n6: ObfuscatedKey { return ObfuscatedKey(_value + "6") }
var n7: ObfuscatedKey { return ObfuscatedKey(_value + "7") }
var n8: ObfuscatedKey { return ObfuscatedKey(_value + "8") }
var n9: ObfuscatedKey { return ObfuscatedKey(_value + "9") }

var dot: ObfuscatedKey { return ObfuscatedKey(_value + ".") }
var dash: ObfuscatedKey { return ObfuscatedKey(_value + "-") }
var underscore: ObfuscatedKey { return ObfuscatedKey(_value + "_") }

func literal(_ extra: String) -> ObfuscatedKey {
return ObfuscatedKey(_value + extra)
}
// codebeat:enable[TOO_MANY_FUNCTIONS]
}
5 changes: 4 additions & 1 deletion Sources/UtiliKit/TimelessDate/TimelessDate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ extension Calendar {
public struct TimelessDate: Comparable, Equatable, Hashable {
private(set) var date: Date
private var calendar = Calendar.current


// codebeat:disable[TOO_MANY_FUNCTIONS]

/**
Returns the DateInterval between the TimelessDate and 1 January 2001.

Expand Down Expand Up @@ -194,6 +196,7 @@ public struct TimelessDate: Comparable, Equatable, Hashable {
public static func ==(lhs: TimelessDate, rhs: TimelessDate) -> Bool {
return lhs.dateIntervalSinceReferenceDate == rhs.dateIntervalSinceReferenceDate
}
// codebeat:enable[TOO_MANY_FUNCTIONS]
}

// MARK: CustomStringConvertable
Expand Down
44 changes: 44 additions & 0 deletions Tests/ObfuscationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// ObfuscationTests.swift
// UtiliKit-iOSTests
//
// Created by Russell Mirabelli on 7/23/19.
// Copyright © 2019 Bottle Rocket Studios. All rights reserved.
//

import XCTest
import UtiliKit

class ObfuscationTests: XCTestCase {

func testSimpleObfuscatedString() {
let key = ObfuscatedKey().A.B.A.B.value
let expected = "ABAB"
XCTAssertEqual(key, expected, "Keys do not match: \(key) is not \(expected)")
}

func testUppercase() {
let key = ObfuscatedKey().A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.value
let expected = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
XCTAssertEqual(key, expected, "Keys do not match: \(key) is not \(expected)")
}

func testLowercase() {
let key = ObfuscatedKey().a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.value
let expected = "abcdefghijklmnopqrstuvwxyz"
XCTAssertEqual(key, expected, "Keys do not match: \(key) is not \(expected)")
}

func testDigits() {
let key = ObfuscatedKey().n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.value
let expected = "0123456789"
XCTAssertEqual(key, expected, "Keys do not match: \(key) is not \(expected)")
}

func testExtras() {
let key = ObfuscatedKey().dot.dash.underscore.literal("=").value
let expected = ".-_="
XCTAssertEqual(key, expected, "Keys do not match: \(key) is not \(expected)")
}

}
4 changes: 4 additions & 0 deletions UtiliKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,8 @@ s.subspec 'ActiveLabel' do |activeLabel|
activeLabel.source_files = 'Sources/UtiliKit/ActiveLabel/*.swift'
end

s.subspec 'Obfuscation' do |obfuscation|
obfuscation.source_files = 'Sources/UtiliKit/Obfuscation/*.swift'
end

end
18 changes: 17 additions & 1 deletion UtiliKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
5C574BFF22675A51003D1641 /* SnapshotTesting.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5C574BFC22675999003D1641 /* SnapshotTesting.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
62F5256D2257F4F50052B8E7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 62F5256C2257F4F50052B8E7 /* README.md */; };
62F5256F2257F4FE0052B8E7 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 62F5256E2257F4FE0052B8E7 /* CHANGELOG.md */; };
7D5611B822E79AD40017008D /* ObfuscationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D5611B722E79AD40017008D /* ObfuscationTests.swift */; };
7D5611BA22E79B4C0017008D /* ObfuscatedKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D5611B922E79B4C0017008D /* ObfuscatedKey.swift */; };
8677314220601BB400C54343 /* UtiliKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8677313920601BB400C54343 /* UtiliKit.framework */; };
8677315720601D1A00C54343 /* UtiliKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 869826261FE87BFA0024B73D /* UtiliKitTests.swift */; };
8677315820601D1A00C54343 /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 869826271FE87BFA0024B73D /* DateTests.swift */; };
Expand Down Expand Up @@ -107,6 +109,8 @@
5C574BFC22675999003D1641 /* SnapshotTesting.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SnapshotTesting.framework; path = Carthage/Build/iOS/SnapshotTesting.framework; sourceTree = "<group>"; };
62F5256C2257F4F50052B8E7 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
62F5256E2257F4FE0052B8E7 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
7D5611B722E79AD40017008D /* ObfuscationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObfuscationTests.swift; sourceTree = "<group>"; };
7D5611B922E79B4C0017008D /* ObfuscatedKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObfuscatedKey.swift; sourceTree = "<group>"; };
8677313920601BB400C54343 /* UtiliKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UtiliKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8677314120601BB400C54343 /* UtiliKit-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UtiliKit-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
8677315A20601DD800C54343 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -237,6 +241,7 @@
isa = PBXGroup;
children = (
869826271FE87BFA0024B73D /* DateTests.swift */,
7D5611B722E79AD40017008D /* ObfuscationTests.swift */,
869826261FE87BFA0024B73D /* UtiliKitTests.swift */,
0ED9476220FD461300B642AB /* ContainerTests.swift */,
5C574BFA2264ED61003D1641 /* ActiveLabelTests.swift */,
Expand All @@ -245,6 +250,14 @@
path = Tests;
sourceTree = "<group>";
};
7D5611B622E79AAE0017008D /* Obfuscation */ = {
isa = PBXGroup;
children = (
7D5611B922E79B4C0017008D /* ObfuscatedKey.swift */,
);
path = Obfuscation;
sourceTree = "<group>";
};
8677315920601DD800C54343 /* Supporting Files */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -278,6 +291,7 @@
8698CFA220619EAD0065AE20 /* Container */,
8698CFA720619EAD0065AE20 /* General */,
8698CFAA20619EAD0065AE20 /* Instantiation */,
7D5611B622E79AAE0017008D /* Obfuscation */,
8698CFB220619EAD0065AE20 /* TimelessDate */,
8698CFB520619EAD0065AE20 /* Version */,
);
Expand Down Expand Up @@ -503,7 +517,7 @@
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = CocoaPods;
ORGANIZATIONNAME = "Bottle Rocket Studios";
TargetAttributes = {
8677313820601BB400C54343 = {
CreatedOnToolsVersion = 9.2;
Expand Down Expand Up @@ -592,6 +606,7 @@
0EC8025C209CE9C90051F732 /* Configurable.swift in Sources */,
8698CFC820619EAD0065AE20 /* TimelessDate.swift in Sources */,
8698CFC320619EAD0065AE20 /* StoryboardIdentifiable.swift in Sources */,
7D5611BA22E79B4C0017008D /* ObfuscatedKey.swift in Sources */,
8698CFC920619EAD0065AE20 /* Bundle+Extensions.swift in Sources */,
8698CFC520619EAD0065AE20 /* UIStoryboard+Extensions.swift in Sources */,
8698CFC220619EAD0065AE20 /* ReuseIdentifiable.swift in Sources */,
Expand All @@ -615,6 +630,7 @@
0ED9476420FD473700B642AB /* ContainerTests.swift in Sources */,
8677315720601D1A00C54343 /* UtiliKitTests.swift in Sources */,
8677315820601D1A00C54343 /* DateTests.swift in Sources */,
7D5611B822E79AD40017008D /* ObfuscationTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down