Skip to content

Commit

Permalink
Added passkey remote methods to verify auth with passkey
Browse files Browse the repository at this point in the history
  • Loading branch information
charliescheer committed Jul 16, 2024
1 parent 8d6419f commit 0dbf126
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 3 deletions.
12 changes: 12 additions & 0 deletions Simplenote.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@
BA71EC242BC88FD000F42CB1 /* CSSearchable+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA52005A2BC878F1003F1B75 /* CSSearchable+Helpers.swift */; };
BA71EC252BC88FFC00F42CB1 /* NSManagedObjectContext+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA52005C2BC88397003F1B75 /* NSManagedObjectContext+Simplenote.swift */; };
BA7575E62C45E269009C08FC /* BlockingActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7575E52C45E269009C08FC /* BlockingActivityIndicator.swift */; };
BA7575E82C46FAF9009C08FC /* PasskeyAuthChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7575E72C46FAF9009C08FC /* PasskeyAuthChallenge.swift */; };
BA7575EA2C46FB07009C08FC /* PasskeyAuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7575E92C46FB07009C08FC /* PasskeyAuthResponse.swift */; };
BA7575EC2C46FB0B009C08FC /* PasskeyVerifyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7575EB2C46FB0B009C08FC /* PasskeyVerifyResponse.swift */; };
BA78AF712B5B2BC300DCF896 /* AutomatticTracks in Frameworks */ = {isa = PBXBuildFile; productRef = BA78AF702B5B2BC300DCF896 /* AutomatticTracks */; };
BA938CEE26AD055400BE5A1D /* AccountVerificationController+TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA938CED26AD055400BE5A1D /* AccountVerificationController+TestHelpers.swift */; };
BA94CB652C0E46CC00B34EA7 /* Uploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA94CB642C0E46CC00B34EA7 /* Uploader.swift */; };
Expand Down Expand Up @@ -783,6 +786,9 @@
BA6689692C45C60E009D4E84 /* PasskeyRegistrator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasskeyRegistrator.swift; sourceTree = "<group>"; };
BA66896B2C45C64C009D4E84 /* PasskeyTypeAliases.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasskeyTypeAliases.swift; sourceTree = "<group>"; };
BA7575E52C45E269009C08FC /* BlockingActivityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockingActivityIndicator.swift; sourceTree = "<group>"; };
BA7575E72C46FAF9009C08FC /* PasskeyAuthChallenge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasskeyAuthChallenge.swift; sourceTree = "<group>"; };
BA7575E92C46FB07009C08FC /* PasskeyAuthResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasskeyAuthResponse.swift; sourceTree = "<group>"; };
BA7575EB2C46FB0B009C08FC /* PasskeyVerifyResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasskeyVerifyResponse.swift; sourceTree = "<group>"; };
BA8CF21B2BFD20770087F33D /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
BA938CEB26ACFF4A00BE5A1D /* Remote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Remote.swift; sourceTree = "<group>"; };
BA938CED26AD055400BE5A1D /* AccountVerificationController+TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountVerificationController+TestHelpers.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1702,6 +1708,9 @@
BA6689652C45C54B009D4E84 /* PasskeyRegistrationResponse.swift */,
BA6689672C45C59E009D4E84 /* PasskeyError.swift */,
BA66896B2C45C64C009D4E84 /* PasskeyTypeAliases.swift */,
BA7575E72C46FAF9009C08FC /* PasskeyAuthChallenge.swift */,
BA7575E92C46FB07009C08FC /* PasskeyAuthResponse.swift */,
BA7575EB2C46FB0B009C08FC /* PasskeyVerifyResponse.swift */,
);
name = Passkeys;
sourceTree = "<group>";
Expand Down Expand Up @@ -2108,6 +2117,7 @@
B5E086292448B57200DEF476 /* HeaderTableCellView.swift in Sources */,
375D294721E033D1007AB25A /* version.c in Sources */,
466FFEA917CC10A800399652 /* SimplenoteAppDelegate.m in Sources */,
BA7575E82C46FAF9009C08FC /* PasskeyAuthChallenge.swift in Sources */,
B5D3FCCD201F906E00A813B7 /* StatusChecker.m in Sources */,
B52EE32825927D5100347F2B /* NoteListViewController.swift in Sources */,
B542FE4B25D42E7B00A3582D /* NoteContentHelper.swift in Sources */,
Expand Down Expand Up @@ -2218,6 +2228,7 @@
B5070E17245938D600715BCC /* NSUserInterfaceItemIdentifier+Simplenote.swift in Sources */,
BAAA71F32C07AB8E00244C01 /* IntentsConstants.swift in Sources */,
B5C6334A251E6E3200C8BF46 /* LinkTableCellView.swift in Sources */,
BA7575EA2C46FB07009C08FC /* PasskeyAuthResponse.swift in Sources */,
BAA0A88B26BA39150006260E /* Date+Simplenote.swift in Sources */,
B542FE4725D42E6D00A3582D /* SearchMapView.swift in Sources */,
B57CB875244DEBC300BA7969 /* Options.swift in Sources */,
Expand Down Expand Up @@ -2251,6 +2262,7 @@
B587D7E22C220765006645CF /* URLSessionProtocol.swift in Sources */,
B58117E325B9E5D200927E0C /* AccountVerificationController.swift in Sources */,
B5F5414925EFFC2200CAF52C /* SignupRemote.swift in Sources */,
BA7575EC2C46FB0B009C08FC /* PasskeyVerifyResponse.swift in Sources */,
B5EB3AD82458CDB50089858D /* ThemeOption.swift in Sources */,
BA6689682C45C59E009D4E84 /* PasskeyError.swift in Sources */,
B59848831BCDB95A005EFBBE /* SPTracker.m in Sources */,
Expand Down
8 changes: 7 additions & 1 deletion Simplenote/AuthViewController+Swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,13 @@ extension AuthViewController {
self.setInterfaceEnabled(true)
}
}


@objc
func performPasskeyAuthentication() {
//TODO: Login with Passkeys
print("# Logging in with passkeys!!!!")
}

@objc
func performLoginWithEmailRequest() {
Task {
Expand Down
3 changes: 1 addition & 2 deletions Simplenote/AuthViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ - (void)pressedLoginWithPasskey {
return;
}

//TODO: Login with passkey
NSLog(@"# Logging in with passkeys!!");
[self performPasskeyAuthentication];
}

- (void)pressedSignUp {
Expand Down
11 changes: 11 additions & 0 deletions Simplenote/PasskeyAuthChallenge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

struct PasskeyAuthChallenge: Decodable {
let relayingParty: String
let challenge: String

enum CodingKeys: String, CodingKey {
case relayingParty = "rpId"
case challenge
}
}
22 changes: 22 additions & 0 deletions Simplenote/PasskeyAuthResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Foundation
import AuthenticationServices

struct PasskeyAuthResponse: Codable {
let id: String
let rawId: String
let response: Response
var type: String = "public-key"

init(from credential: ASAuthorizationPlatformPublicKeyCredentialAssertion) {
self.id = credential.credentialID.base64EncodedString().toBase64url()
self.rawId = credential.credentialID.base64EncodedString().toBase64url()
self.response = PasskeyAuthResponse.Response(clientDataJSON: credential.rawClientDataJSON.base64EncodedString(), authenticatorData: credential.rawAuthenticatorData.base64EncodedString(), signature: credential.signature.base64EncodedString(), userHandle: credential.userID.base64EncodedString())
}

struct Response: Codable {
let clientDataJSON: String
let authenticatorData: String
let signature: String
let userHandle: String
}
}
13 changes: 13 additions & 0 deletions Simplenote/PasskeyVerifyResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

struct PasskeyVerifyResponse: Decodable {
let username: String
let accessToken: String
let verified: Bool

enum CodingKeys: String, CodingKey {
case username
case accessToken = "access_token"
case verified
}
}
2 changes: 2 additions & 0 deletions Simplenote/SimplenoteConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ class SimplenoteConstants: NSObject {
static let currentPasskeyBaseURL = URL(string: "https://passkey-dev-dot-simple-note-hrd.appspot.com")!
static let passkeyCredentialCreationURL = currentPasskeyBaseURL.appendingPathComponent("/api2/login")
static let passkeyRegistrationURL = currentPasskeyBaseURL.appendingPathComponent("/auth/add-credential")
static let passkeyAuthChallengeURL = currentPasskeyBaseURL.appendingPathComponent("/auth/prepare-auth-challenge")
static let verifyPasskeyAuthChallengeURL = currentPasskeyBaseURL.appendingPathComponent("/auth/verify-login-credential")
}
42 changes: 42 additions & 0 deletions SimplenoteTests/PasskeyRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,46 @@ class PasskeyRemote: Remote {
let request = requestForPasskeyCredentialRegistration(withData: data)
try await _ = performDataTask(with: request)
}

private func passkeyAuthChallengeRequest(forEmail email: String) -> URLRequest {
var urlRequest = URLRequest(url: SimplenoteConstants.passkeyAuthChallengeURL)
urlRequest.httpMethod = RemoteConstants.Method.POST
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")

let body = [
"email": email.lowercased()
]
let json = try? JSONEncoder().encode(body)

urlRequest.httpBody = json

return urlRequest
}

func passkeyAuthChallenge(for email: String) async throws -> PasskeyAuthChallenge {
let request = passkeyAuthChallengeRequest(forEmail: email)
let data = try await performDataTask(with: request)

return try JSONDecoder().decode(PasskeyAuthChallenge.self, from: data)
}

private func verifyPassKeyRequest(with data: Data) -> URLRequest {
var urlRequest = URLRequest(url: SimplenoteConstants.verifyPasskeyAuthChallengeURL)
urlRequest.httpMethod = RemoteConstants.Method.POST
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = data

return urlRequest
}

func verifyPasskeyLogin(with response: PasskeyAuthResponse) async throws -> PasskeyVerifyResponse {
guard let data = try? JSONEncoder().encode(response) else {
throw PasskeyError.authFailed
}

let request = verifyPassKeyRequest(with: data)
let verify = try await performDataTask(with: request)

return try JSONDecoder().decode(PasskeyVerifyResponse.self, from: verify)
}
}

0 comments on commit 0dbf126

Please sign in to comment.