Skip to content

Commit

Permalink
Initial landing of partial Sync, Token Server, and FxA Swift code.
Browse files Browse the repository at this point in the history
  • Loading branch information
rnewman committed Nov 19, 2014
1 parent b6bcc66 commit 9fe5042
Show file tree
Hide file tree
Showing 12 changed files with 1,952 additions and 0 deletions.
925 changes: 925 additions & 0 deletions FxA/FxA.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions FxA/FxA.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
110 changes: 110 additions & 0 deletions FxA/FxA.xcodeproj/xcshareddata/xcschemes/FxA.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0600"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "28F951FA19D0F9FA00DCE892"
BuildableName = "FxA.framework"
BlueprintName = "FxA"
ReferencedContainer = "container:FxA.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "28F9520519D0F9FB00DCE892"
BuildableName = "FxATests.xctest"
BlueprintName = "FxATests"
ReferencedContainer = "container:FxA.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "28F9520519D0F9FB00DCE892"
BuildableName = "FxATests.xctest"
BlueprintName = "FxATests"
ReferencedContainer = "container:FxA.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "28F951FA19D0F9FA00DCE892"
BuildableName = "FxA.framework"
BlueprintName = "FxA"
ReferencedContainer = "container:FxA.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "28F951FA19D0F9FA00DCE892"
BuildableName = "FxA.framework"
BlueprintName = "FxA"
ReferencedContainer = "container:FxA.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "28F951FA19D0F9FA00DCE892"
BuildableName = "FxA.framework"
BlueprintName = "FxA"
ReferencedContainer = "container:FxA.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
128 changes: 128 additions & 0 deletions FxAClient/FxAClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation
import Alamofire

import FxA

public let PROD_AUTH_SERVER_ENDPOINT = "https://api.accounts.firefox.com/v1";
public let STAGE_AUTH_SERVER_ENDPOINT = "https://api-accounts.stage.mozaws.net/v1";

public let FxAClientErrorDomain = "org.mozilla.fxa.error"

public class FxALoginResponse {
public let remoteEmail : String
public let uid : String
public let verified : Bool
public let sessionToken : NSData
public let keyFetchToken: NSData

public init(remoteEmail: String, uid: String, verified: Bool, sessionToken: NSData, keyFetchToken: NSData) {
self.remoteEmail = remoteEmail
self.uid = uid
self.verified = verified
self.sessionToken = sessionToken
self.keyFetchToken = keyFetchToken
}
}

public class FxAClient {
private class var requestManager : Alamofire.Manager {
struct Static {
static let manager : Alamofire.Manager = Alamofire.Manager(configuration: Alamofire.Manager.sharedInstance.session.configuration)
}
Static.manager.startRequestsImmediately = false
return Static.manager
}

public class func quickStretchPW(email: NSData, password: NSData) -> NSData {
let salt: NSMutableData = NSMutableData(data: "identity.mozilla.com/picl/v1/quickStretch:".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
salt.appendData(email)
return password.derivePBKDF2HMACSHA256KeyWithSalt(salt, iterations: 1000, length: 32)
}

private class func validateJSON(json : JSON) -> Bool {
return
json["uid"].isString &&
json["verified"].isBool &&
json["sessionToken"].isString &&
json["keyFetchToken"].isString
}

private class func responseFromJSON(json: JSON) -> FxALoginResponse {
let uid = json["uid"].asString!
let sessionToken = NSData(base16EncodedString: json["sessionToken"].asString!, options: NSDataBase16DecodingOptions.Default)
let keyFetchToken = NSData(base16EncodedString: json["keyFetchToken"].asString!, options: NSDataBase16DecodingOptions.Default)
let verified = json["verified"].asBool!
return FxALoginResponse(remoteEmail: "", uid: uid, verified: verified, sessionToken: sessionToken, keyFetchToken: keyFetchToken)
}

public let url : String

public init(endpoint: String? = nil) {
self.url = endpoint ?? PROD_AUTH_SERVER_ENDPOINT
}

public func login(queue: dispatch_queue_t? = nil, emailUTF8: NSData, quickStretchedPW: NSData, getKeys: Bool, callback: (FxALoginResponse?, NSError?) -> Void) {
let queue = queue ?? dispatch_get_main_queue()

let authPW = quickStretchedPW.deriveHKDFSHA256KeyWithSalt(NSData(), contextInfo: "identity.mozilla.com/picl/v1/authPW".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false), length: 32)

let parameters = [
"email": NSString(data: emailUTF8, encoding: NSUTF8StringEncoding),
"authPW": authPW.base16EncodedStringWithOptions(NSDataBase16EncodingOptions.LowerCase),
]

let url = NSURL(string: self.url + (getKeys ? "/account/login?keys=true" : "/account/login"))
let mutableURLRequest = NSMutableURLRequest(URL: url)
mutableURLRequest.HTTPMethod = Method.POST.toRaw()

let (r, e) = ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters)
if e != nil {
return dispatch_async(queue, {
callback(nil, e)
})
}

let manager = FxAClient.requestManager
let request = manager.request(r)
request.responseJSON { (request, response, json, error) in
if error != nil {
return dispatch_async(queue, {
callback(nil, error)
})
}

if response == nil || json == nil {
return dispatch_async(queue, {
callback(nil, NSError(domain: FxAClientErrorDomain, code: -1, userInfo: ["message": "malformed JSON response"]))
})
}

let json = JSON(json!)

let statusCode : Int = response!.statusCode
if statusCode != 200 {
return dispatch_async(queue, {
callback(nil, NSError(domain: FxAClientErrorDomain, code: -1, userInfo: ["message": "bad response code", "code": statusCode,
"body": json.toString(pretty: true)]))
})
}

if !FxAClient.validateJSON(json) {
return dispatch_async(queue, {
callback(nil, NSError(domain: FxAClientErrorDomain, code: -1, userInfo: ["message": "invalid server response"]))
})
}

let response = FxAClient.responseFromJSON(json)
return dispatch_async(queue, {
callback(response, nil)
})
}

request.resume()
}
}
41 changes: 41 additions & 0 deletions Sync/Bytes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation

/**
* Utilities for futzing with bytes and such.
*/
public class Bytes {
public class func generateRandomBytes(len: UInt) -> NSData {
let data = NSMutableData(length: Int(len))
let bytes = UnsafeMutablePointer<UInt8>(data.mutableBytes)
let result: Int32 = SecRandomCopyBytes(kSecRandomDefault, len, bytes)

assert(result == 0, "Random byte generation failed.");
return data
}

public class func generateGUID() -> String {
return generateRandomBytes(9).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
}

public class func decodeBase64(b64: String) -> NSData {
return NSData(base64EncodedString: b64,
options: NSDataBase64DecodingOptions.allZeros)
}

/**
* Turn a string of base64 characters into an NSData *without decoding*.
* This is to allow HMAC to be computed of the raw base64 string.
*/
public class func dataFromBase64(b64: String) -> NSData? {
return b64.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
}

func fromHex(str: String) -> NSData {
// TODO
return NSData()
}
}
53 changes: 53 additions & 0 deletions Sync/ClientPayload.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation


@objc public class ClientPayload : CleartextPayloadJSON {
override public func isValid() -> Bool {
// We should also call super.isValid(), but that'll fail:
// Global is external, but doesn't have external or weak linkage!
// Swift compiler bug #18422804.
return !isError &&
self["name"].isString &&
self["commands"].isArray &&
self["type"].isString
}

var commands: [JSON] {
return self["commands"].asArray!
}

var name: String {
return self["name"].asString!
}

var clientType: String {
return self["type"].asString!
}

override public func equalPayloads(obj: CleartextPayloadJSON) -> Bool {
if !(obj is ClientPayload) {
return false;
}

if !super.equalPayloads(obj) {
return false;
}

let p = obj as ClientPayload
if p.name != self.name {
return false
}

if p.clientType != self.clientType {
return false;
}

return true
}

// TODO: version, protocols.
}
Loading

0 comments on commit 9fe5042

Please sign in to comment.