Skip to content

Commit f39d3f5

Browse files
committed
Merge pull request #1 from mozilla/master
merge to myslef
2 parents 64be41b + e71424d commit f39d3f5

File tree

1,271 files changed

+248602
-14417
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,271 files changed

+248602
-14417
lines changed

.gitignore

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Xcode
2-
#
32
build/
43
*.pbxuser
54
!default.pbxuser
@@ -16,21 +15,27 @@ DerivedData
1615
*.hmap
1716
*.ipa
1817
*.xcuserstate
18+
*.xcscmblueprint
1919

2020
# OS X
21-
#
2221
.DS_Store
2322

2423
# Vim
2524
*~
25+
.*.sw*
2626

2727
# IDEA
2828
.idea
2929

30-
# CocoaPods
31-
#
32-
# We recommend against adding the Pods directory to your .gitignore. However
33-
# you should judge for yourself, the pros and cons are mentioned at:
34-
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
35-
#
36-
# Pods/
30+
Carthage/
31+
32+
ThirdParty/google-breakpad
33+
34+
# Saved Sync credentials for tests.
35+
signedInUser.json
36+
37+
# Generated config file
38+
MozBuildID.xcconfig
39+
40+
# Python.
41+
*.pyc

.gitmodules

Lines changed: 0 additions & 3 deletions
This file was deleted.

.travis.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
osx_image: beta-xcode6.3
2+
language: objective-c
3+
env:
4+
- LC_CTYPE=en_US.UTF-8 LANG=en_US.UTF-8
5+
before_install:
6+
- gem install xcpretty -N
7+
script:
8+
- set -o pipefail
9+
- brew update
10+
- brew install carthage
11+
- ./checkout.sh
12+
- rm -rf build
13+
- xcodebuild -project Client.xcodeproj -scheme "Firefox" -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 6" ONLY_ACTIVE_ARCH=NO -derivedDataPath build clean test | xcpretty -c
14+
15+
notifications:
16+
email: false
17+
irc:
18+
channels:
19+
- "irc.mozilla.org#firefoxios"
20+
on_success: change
21+
on_failure: always
22+
23+
# This stopped working
24+
# - xctool -project Client.xcodeproj -scheme Travis -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO
25+
# - xctool test -freshSimulator -project Client.xcodeproj -scheme Travis -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO

AUTHORS

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
This is an (incomplete) list of people who have contributed to the
2+
codebase which lives in this repository. If you make a contribution
3+
here, you may add your name and, optionally, email address in the
4+
appropriate place.
5+
6+
For a full list of the people who are credited with making a
7+
contribution to Mozilla, see http://www.mozilla.org/credits/.
8+
9+
Brian Nicholson
10+
Le Van Nghia
11+
Nick Alexander
12+
Richard Newman
13+
Sachin Palewar
14+
Sahil Wasan
15+
Stefan Arentz
16+
Thomas Bonnin
17+
Wes Johnston

Account/Account-Bridging-Header.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef Client_Account_Bridging_Header_h
2+
#define Client_Account_Bridging_Header_h
3+
4+
#import <Foundation/Foundation.h>
5+
6+
#endif

Account/FirefoxAccount.swift

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import Foundation
6+
import Shared
7+
import XCGLogger
8+
9+
private let log = Logger.syncLogger
10+
11+
// The version of the account schema we persist.
12+
let AccountSchemaVersion = 1
13+
14+
/// A FirefoxAccount mediates access to identity attached services.
15+
///
16+
/// All data maintained as part of the account or its state should be
17+
/// considered sensitive and stored appropriately. Usually, that means
18+
/// storing account data in the iOS keychain.
19+
///
20+
/// Non-sensitive but persistent data should be maintained outside of
21+
/// the account itself.
22+
public class FirefoxAccount {
23+
/// The email address identifying the account. A Firefox Account is uniquely identified on a particular server
24+
/// (auth endpoint) by its email address.
25+
public let email: String
26+
27+
/// The auth endpoint user identifier identifying the account. A Firefox Account is uniquely identified on a
28+
/// particular server (auth endpoint) by its assigned uid.
29+
public let uid: String
30+
31+
public let configuration: FirefoxAccountConfiguration
32+
33+
private let stateCache: KeychainCache<FxAState>
34+
public var syncAuthState: SyncAuthState! // We can't give a reference to self if this is a let.
35+
36+
// To prevent advance() consumers racing, we maintain a shared advance() deferred (`advanceDeferred`). If an
37+
// advance() is in progress, the shared deferred will be returned. (Multiple consumers can chain off a single
38+
// deferred safely.) If no advance() is in progress, a new shared deferred will be scheduled and returned. To
39+
// prevent data races against the shared deferred, advance() locks accesses to `advanceDeferred` using
40+
// `advanceLock`.
41+
private var advanceLock = OSSpinLock()
42+
private var advanceDeferred: Deferred<FxAState>? = nil
43+
44+
public var actionNeeded: FxAActionNeeded {
45+
return stateCache.value!.actionNeeded
46+
}
47+
48+
public convenience init(configuration: FirefoxAccountConfiguration, email: String, uid: String, stateKeyLabel: String, state: FxAState) {
49+
self.init(configuration: configuration, email: email, uid: uid, stateCache: KeychainCache(branch: "account.state", label: stateKeyLabel, value: state))
50+
}
51+
52+
public init(configuration: FirefoxAccountConfiguration, email: String, uid: String, stateCache: KeychainCache<FxAState>) {
53+
self.email = email
54+
self.uid = uid
55+
self.configuration = configuration
56+
self.stateCache = stateCache
57+
self.stateCache.checkpoint()
58+
self.syncAuthState = FirefoxAccountSyncAuthState(account: self,
59+
cache: KeychainCache.fromBranch("account.syncAuthState", withLabel: self.stateCache.label, factory: syncAuthStateCachefromJSON))
60+
}
61+
62+
public class func fromConfigurationAndJSON(configuration: FirefoxAccountConfiguration, data: JSON) -> FirefoxAccount? {
63+
if let email = data["email"].asString {
64+
if let uid = data["uid"].asString {
65+
if let sessionToken = data["sessionToken"].asString?.hexDecodedData {
66+
if let keyFetchToken = data["keyFetchToken"].asString?.hexDecodedData {
67+
if let unwrapkB = data["unwrapBKey"].asString?.hexDecodedData {
68+
let verified = data["verified"].asBool ?? false
69+
return FirefoxAccount.fromConfigurationAndParameters(configuration,
70+
email: email, uid: uid, verified: verified,
71+
sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
72+
}
73+
}
74+
}
75+
}
76+
}
77+
return nil
78+
}
79+
80+
public class func fromConfigurationAndLoginResponse(configuration: FirefoxAccountConfiguration,
81+
response: FxALoginResponse, unwrapkB: NSData) -> FirefoxAccount {
82+
return FirefoxAccount.fromConfigurationAndParameters(configuration,
83+
email: response.remoteEmail, uid: response.uid, verified: response.verified,
84+
sessionToken: response.sessionToken, keyFetchToken: response.keyFetchToken, unwrapkB: unwrapkB)
85+
}
86+
87+
private class func fromConfigurationAndParameters(configuration: FirefoxAccountConfiguration,
88+
email: String, uid: String, verified: Bool,
89+
sessionToken: NSData, keyFetchToken: NSData, unwrapkB: NSData) -> FirefoxAccount {
90+
var state: FxAState! = nil
91+
if !verified {
92+
let now = NSDate.now()
93+
state = EngagedBeforeVerifiedState(knownUnverifiedAt: now,
94+
lastNotifiedUserAt: now,
95+
sessionToken: sessionToken,
96+
keyFetchToken: keyFetchToken,
97+
unwrapkB: unwrapkB
98+
)
99+
} else {
100+
state = EngagedAfterVerifiedState(
101+
sessionToken: sessionToken,
102+
keyFetchToken: keyFetchToken,
103+
unwrapkB: unwrapkB
104+
)
105+
}
106+
107+
let account = FirefoxAccount(
108+
configuration: configuration,
109+
email: email,
110+
uid: uid,
111+
stateKeyLabel: Bytes.generateGUID(),
112+
state: state
113+
)
114+
return account
115+
}
116+
117+
public func asDictionary() -> [String: AnyObject] {
118+
var dict: [String: AnyObject] = [:]
119+
dict["version"] = AccountSchemaVersion
120+
dict["email"] = email
121+
dict["uid"] = uid
122+
dict["configurationLabel"] = configuration.label.rawValue
123+
dict["stateKeyLabel"] = stateCache.label
124+
return dict
125+
}
126+
127+
public class func fromDictionary(dictionary: [String: AnyObject]) -> FirefoxAccount? {
128+
if let version = dictionary["version"] as? Int {
129+
if version == AccountSchemaVersion {
130+
return FirefoxAccount.fromDictionaryV1(dictionary)
131+
}
132+
}
133+
return nil
134+
}
135+
136+
private class func fromDictionaryV1(dictionary: [String: AnyObject]) -> FirefoxAccount? {
137+
var configurationLabel: FirefoxAccountConfigurationLabel? = nil
138+
if let rawValue = dictionary["configurationLabel"] as? String {
139+
configurationLabel = FirefoxAccountConfigurationLabel(rawValue: rawValue)
140+
}
141+
if let
142+
configurationLabel = configurationLabel,
143+
email = dictionary["email"] as? String,
144+
uid = dictionary["uid"] as? String {
145+
let stateCache = KeychainCache.fromBranch("account.state", withLabel: dictionary["stateKeyLabel"] as? String, withDefault: SeparatedState(), factory: stateFromJSON)
146+
return FirefoxAccount(
147+
configuration: configurationLabel.toConfiguration(),
148+
email: email, uid: uid,
149+
stateCache: stateCache)
150+
}
151+
return nil
152+
}
153+
154+
public enum AccountError: MaybeErrorType {
155+
case NotMarried
156+
157+
public var description: String {
158+
switch self {
159+
case NotMarried: return "Not married."
160+
}
161+
}
162+
}
163+
164+
public func advance() -> Deferred<FxAState> {
165+
OSSpinLockLock(&advanceLock)
166+
if let deferred = advanceDeferred {
167+
// We already have an advance() in progress. This consumer can chain from it.
168+
log.debug("advance already in progress; returning shared deferred.")
169+
OSSpinLockUnlock(&advanceLock)
170+
return deferred
171+
}
172+
173+
// Alright, we haven't an advance() in progress. Schedule a new deferred to chain from.
174+
let client = FxAClient10(endpoint: configuration.authEndpointURL)
175+
let stateMachine = FxALoginStateMachine(client: client)
176+
let now = NSDate.now()
177+
let deferred: Deferred<FxAState> = stateMachine.advanceFromState(stateCache.value!, now: now).map { newState in
178+
self.stateCache.value = newState
179+
return newState
180+
}
181+
advanceDeferred = deferred
182+
log.debug("no advance() in progress; setting and returning new shared deferred.")
183+
OSSpinLockUnlock(&advanceLock)
184+
185+
deferred.upon { _ in
186+
// This advance() is complete. Clear the shared deferred.
187+
OSSpinLockLock(&self.advanceLock)
188+
if let existingDeferred = self.advanceDeferred where existingDeferred === deferred {
189+
// The guard should not be needed, but should prevent trampling racing consumers.
190+
self.advanceDeferred = nil
191+
log.debug("advance() completed and shared deferred is existing deferred; clearing shared deferred.")
192+
} else {
193+
log.warning("advance() completed but shared deferred is not existing deferred; ignoring potential bug!")
194+
}
195+
OSSpinLockUnlock(&self.advanceLock)
196+
}
197+
return deferred
198+
}
199+
200+
public func marriedState() -> Deferred<Maybe<MarriedState>> {
201+
return advance().map { newState in
202+
if newState.label == FxAStateLabel.Married {
203+
if let married = newState as? MarriedState {
204+
return Maybe(success: married)
205+
}
206+
}
207+
return Maybe(failure: AccountError.NotMarried)
208+
}
209+
}
210+
211+
public func makeSeparated() -> Bool {
212+
log.info("Making Account State be Separated.")
213+
self.stateCache.value = SeparatedState()
214+
return true
215+
}
216+
217+
public func makeDoghouse() -> Bool {
218+
log.info("Making Account State be Doghouse.")
219+
self.stateCache.value = DoghouseState()
220+
return true
221+
}
222+
223+
public func makeCohabitingWithoutKeyPair() -> Bool {
224+
if let married = self.stateCache.value as? MarriedState {
225+
log.info("Making Account State be CohabitingWithoutKeyPair.")
226+
self.stateCache.value = married.withoutKeyPair()
227+
return true
228+
}
229+
log.info("Cannot make Account State be CohabitingWithoutKeyPair from state with label \(self.stateCache.value?.label).")
230+
return false
231+
}
232+
}

0 commit comments

Comments
 (0)