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

fix: Update to user password should persist new sessionToken to Keychain #147

Merged
merged 3 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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