Skip to content

Commit

Permalink
fix: Update to user password should persist new sessionToken to Keych…
Browse files Browse the repository at this point in the history
…ain (#147)

* fix: Update to user password should persist new sessionToken to Keychain

* update sessionToken on merge and non-merged users
  • Loading branch information
cbaker6 authored Jan 12, 2024
1 parent 32a96a4 commit dc037bd
Show file tree
Hide file tree
Showing 31 changed files with 611 additions and 330 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.2...5.9.0), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.9.0/documentation/parseswift)

__New features__
* Cocoapods now defaults to Swift 5.9 ([#146](https://github.com/netreconlab/Parse-Swift/pull/146)), thanks to [Corey Baker](https://github.com/cbaker6).
* Add support for visionOS ([#143](https://github.com/netreconlab/Parse-Swift/pull/143)), thanks to [Corey Baker](https://github.com/cbaker6).
* Add fetchAll method to array of Parse Pointer Object's ([#141](https://github.com/netreconlab/Parse-Swift/pull/141)), thanks to [Corey Baker](https://github.com/cbaker6).

__Fixes__
* Updates to ParseUser password now persist the updated sessionToken from the server to the client Keychain ([#147](https://github.com/netreconlab/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).

### 5.8.2
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.1...5.8.2), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.8.2/documentation/parseswift)

Expand Down
124 changes: 94 additions & 30 deletions Sources/ParseSwift/API/Responses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,93 @@ struct CreateResponse: Decodable {
var updatedAt: Date {
return createdAt
}
var sessionToken: String?

func apply<T>(to object: T) -> T where T: ParseObject {
func setResponseProperties<T>(on object: T) -> T where T: ParseObject {
var object = object
object.objectId = objectId
object.createdAt = createdAt
object.updatedAt = updatedAt
return object
}

func apply<T>(to object: T) -> T where T: ParseObject {
setResponseProperties(on: object)
}

func apply<T>(to user: T) -> T where T: ParseUser {
var user = setResponseProperties(on: user)
user.password = nil
return user
}

}

struct ReplaceResponse: Decodable {
var createdAt: Date?
var updatedAt: Date?
var sessionToken: String?

func apply<T>(to object: T) throws -> T where T: ParseObject {
func setResponseProperties<T>(on object: T) throws -> T where T: ParseObject {
guard let objectId = object.objectId else {
throw ParseError(code: .missingObjectId,
message: "Response from server should not have an objectId of nil")
throw ParseError(
code: .missingObjectId,
message: "Response from server should not have an objectId of nil"
)
}
guard let createdAt = createdAt else {
guard let updatedAt = updatedAt else {
throw ParseError(code: .otherCause,
message: "Response from server should not have an updatedAt of nil")
throw ParseError(
code: .otherCause,
message: "Response from server should not have an updatedAt of nil"
)
}
return UpdateResponse(updatedAt: updatedAt).apply(to: object)
let response = UpdateResponse(
updatedAt: updatedAt,
sessionToken: sessionToken
).apply(to: object)

return response
}
return CreateResponse(objectId: objectId,
createdAt: createdAt).apply(to: object)
let response = CreateResponse(
objectId: objectId,
createdAt: createdAt,
sessionToken: sessionToken
).apply(to: object)

return response
}

func apply<T>(to object: T) throws -> T where T: ParseObject {
try setResponseProperties(on: object)
}

func apply<T>(to user: T) throws -> T where T: ParseUser {
var user = try setResponseProperties(on: user)
user.password = nil // password should be removed
return user
}
}

struct UpdateResponse: Decodable {
var updatedAt: Date
var sessionToken: String?

func apply<T>(to object: T) -> T where T: ParseObject {
func setResponseProperties<T>(on object: T) -> T where T: ParseObject {
var object = object
object.updatedAt = updatedAt
return object
}
}

struct UpdateSessionTokenResponse: Decodable {
var updatedAt: Date
let sessionToken: String?
func apply<T>(to object: T) -> T where T: ParseObject {
setResponseProperties(on: object)
}

func apply<T>(to user: T) -> T where T: ParseUser {
var user = setResponseProperties(on: user)
user.password = nil // password should be removed
return user
}
}

// MARK: ParseObject Batch
Expand All @@ -70,29 +113,50 @@ struct BatchResponse: Codable {
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var sessionToken: String?

func asCreateResponse() throws -> CreateResponse {
guard let objectId = objectId else {
throw ParseError(code: .missingObjectId,
message: "Response from server should not have an objectId of nil")
throw ParseError(
code: .missingObjectId,
message: "Response from server should not have an objectId of nil"
)
}
guard let createdAt = createdAt else {
throw ParseError(code: .otherCause,
message: "Response from server should not have an createdAt of nil")
throw ParseError(
code: .otherCause,
message: "Response from server should not have an createdAt of nil"
)
}
return CreateResponse(objectId: objectId, createdAt: createdAt)

let response = CreateResponse(
objectId: objectId,
createdAt: createdAt, sessionToken: sessionToken
)

return response
}

func asReplaceResponse() -> ReplaceResponse {
ReplaceResponse(createdAt: createdAt, updatedAt: updatedAt)
ReplaceResponse(
createdAt: createdAt,
updatedAt: updatedAt,
sessionToken: sessionToken
)
}

func asUpdateResponse() throws -> UpdateResponse {
guard let updatedAt = updatedAt else {
throw ParseError(code: .otherCause,
message: "Response from server should not have an updatedAt of nil")
throw ParseError(
code: .otherCause,
message: "Response from server should not have an updatedAt of nil"
)
}
return UpdateResponse(updatedAt: updatedAt)
let response = UpdateResponse(
updatedAt: updatedAt,
sessionToken: sessionToken
)
return response
}

func apply<T>(to object: T, method: API.Method) throws -> T where T: ParseObject {
Expand Down Expand Up @@ -125,14 +189,14 @@ struct LoginSignupResponse: Codable {
var updatedAt: Date?
let username: String?

func applySignup<T>(to object: T) -> T where T: ParseUser {
var object = object
object.objectId = objectId
object.createdAt = createdAt
object.updatedAt = createdAt
object.password = nil // password should be removed
func apply<T>(to user: T) -> T where T: ParseUser {
var user = user
user.objectId = objectId
user.createdAt = createdAt
user.updatedAt = updatedAt ?? createdAt
user.password = nil // password should be removed

return object
return user
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,8 @@ public extension ParseUser {
return API.Command<Self, Self>(method: .PUT,
path: endpoint,
body: mutableSelf) { (data) -> Self in
let user = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: data)
mutableSelf.updatedAt = user.updatedAt
let user = try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: data)
mutableSelf = user.apply(to: mutableSelf)
if let sessionToken = user.sessionToken {
await Self.setCurrentContainer(.init(currentUser: mutableSelf,
sessionToken: sessionToken))
Expand All @@ -434,9 +434,8 @@ public extension ParseUser {
return API.Command<SignupLoginBody, Self>(method: .PUT,
path: endpoint,
body: body) { (data) -> Self in
let user = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: data)
var currentUser = currentStrippedUser
currentUser.updatedAt = user.updatedAt
let user = try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: data)
var currentUser = user.apply(to: currentStrippedUser)
currentUser.authData = body.authData
if let sessionToken = user.sessionToken {
await Self.setCurrentContainer(.init(currentUser: currentUser,
Expand Down
4 changes: 3 additions & 1 deletion Sources/ParseSwift/Objects/ParseUser+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,9 @@ internal extension ParseUser {
let command: API.Command<Self, Self>!
switch method {
case .save:
command = try await self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)
command = try await self.saveCommand(
ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig
)
case .create:
command = try await self.createCommand()
case .replace:
Expand Down
Loading

0 comments on commit dc037bd

Please sign in to comment.