Skip to content

Commit 3bed0e7

Browse files
authored
Update native sdks (#163)
1 parent cabb7f2 commit 3bed0e7

31 files changed

+578
-393
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 0.9.10
2+
- Update Descope native SDKs
3+
14
# 0.9.9
25

36
- Introducing the `DescopeFlowView` widget for seamless integration of Descope Flows in Flutter applications. Available for both Android and iOS platforms.

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ android {
5151
implementation "androidx.browser:browser:1.8.0"
5252
implementation "androidx.security:security-crypto:1.1.0"
5353
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2"
54-
implementation "com.descope:descope-kotlin:0.17.1"
54+
implementation "com.descope:descope-kotlin:0.17.3"
5555
}
5656

5757
testOptions {

ios/Classes/descope-swift-sdk/flows/FlowBridge.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,26 @@ window.descopeBridge = {
548548
} else {
549549
window.webkit.messageHandlers.\(FlowBridgeMessage.ready.rawValue).postMessage(tag)
550550
}
551+
this.disableTouchInteractions()
552+
},
553+
554+
disableTouchInteractions() {
555+
this.component.injectStyle?.(`
556+
#content-root * {
557+
-webkit-touch-callout: none;
558+
-webkit-user-select: none;
559+
}
560+
`)
561+
562+
this.component.shadowRoot?.querySelectorAll('descope-enriched-text').forEach(t => {
563+
t.shadowRoot?.querySelectorAll('a').forEach(a => {
564+
a.draggable = false
565+
})
566+
})
567+
568+
this.component.shadowRoot?.querySelectorAll('img').forEach(a => {
569+
a.draggable = false
570+
})
551571
},
552572
553573
updateRefreshJwt(refreshJwt) {

ios/Classes/descope-swift-sdk/flows/FlowCoordinator.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,8 @@ public class DescopeFlowCoordinator {
323323
private func parseAuthentication(_ data: Data) async -> AuthenticationResponse? {
324324
do {
325325
guard let webView else { return nil }
326-
let cookies = await webView.configuration.websiteDataStore.httpCookieStore.cookies(for: webView.url)
327326
var jwtResponse = try JSONDecoder().decode(DescopeClient.JWTResponse.self, from: data)
327+
let cookies = await webView.configuration.websiteDataStore.httpCookieStore.cookies(for: jwtResponse.cookieDomain, at: webView.url)
328328
try jwtResponse.setValues(from: data, cookies: cookies, refreshCookieName: bridge.attributes.refreshCookieName)
329329
return try jwtResponse.convert()
330330
} catch {
@@ -417,13 +417,18 @@ extension DescopeFlowCoordinator: FlowBridgeDelegate {
417417
}
418418

419419
private extension WKHTTPCookieStore {
420-
func cookies(for url: URL?) async -> [HTTPCookie] {
420+
func cookies(for domain: String?, at url: URL?) async -> [HTTPCookie] {
421421
return await allCookies().filter { cookie in
422-
guard let domain = url?.host else { return true }
423-
if cookie.domain.hasPrefix(".") {
424-
return domain.hasSuffix(cookie.domain) || domain == cookie.domain.dropFirst()
422+
// prefer finding value cookies compared to the cookie domain if it's specified,
423+
// but allow falling back to comparing against the page URL
424+
for value in [domain, url?.host] {
425+
guard let value, !value.isEmpty else { continue }
426+
if cookie.domain.hasPrefix(".") {
427+
return value.hasSuffix(cookie.domain) || value == cookie.domain.dropFirst()
428+
}
429+
return value == cookie.domain
425430
}
426-
return domain == cookie.domain
431+
return true
427432
}
428433
}
429434
}

ios/Classes/descope-swift-sdk/internal/http/DescopeClient.swift

Lines changed: 58 additions & 48 deletions
Large diffs are not rendered by default.

ios/Classes/descope-swift-sdk/internal/http/HTTPClient.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,25 @@ class HTTPClient {
1414

1515
// Convenience response functions
1616

17-
final func get<T: JSONResponse>(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:]) async throws -> T {
17+
final func get<T: JSONResponse>(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:]) async throws(DescopeError) -> T {
1818
let (data, response) = try await get(route, headers: headers, params: params)
1919
return try decodeJSON(data: data, response: response)
2020
}
2121

22-
final func post<T: JSONResponse>(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:], body: [String: Any?] = [:]) async throws -> T {
22+
final func post<T: JSONResponse>(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:], body: [String: Any?] = [:]) async throws(DescopeError) -> T {
2323
let (data, response) = try await post(route, headers: headers, params: params, body: body)
2424
return try decodeJSON(data: data, response: response)
2525
}
2626

2727
// Convenience data functions
2828

2929
@discardableResult
30-
final func get(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:]) async throws -> (Data, HTTPURLResponse) {
30+
final func get(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:]) async throws(DescopeError) -> (Data, HTTPURLResponse) {
3131
return try await call(route, method: "GET", headers: headers, params: params, body: nil)
3232
}
3333

3434
@discardableResult
35-
final func post(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:], body: [String: Any?] = [:]) async throws -> (Data, HTTPURLResponse) {
35+
final func post(_ route: String, headers: [String: String] = [:], params: [String: String?] = [:], body: [String: Any?] = [:]) async throws(DescopeError) -> (Data, HTTPURLResponse) {
3636
return try await call(route, method: "POST", headers: headers, params: params, body: encodeJSON(body))
3737
}
3838

@@ -56,7 +56,7 @@ class HTTPClient {
5656

5757
// Private
5858

59-
private func call(_ route: String, method: String, headers: [String: String], params: [String: String?], body: Data?) async throws -> (Data, HTTPURLResponse) {
59+
private func call(_ route: String, method: String, headers: [String: String], params: [String: String?], body: Data?) async throws(DescopeError) -> (Data, HTTPURLResponse) {
6060
let request = try makeRequest(route: route, method: method, headers: headers, params: params, body: body)
6161
if logger.isUnsafeEnabled {
6262
logger.info("Starting network call", request.url)
@@ -110,7 +110,7 @@ class HTTPClient {
110110
return (data, response)
111111
}
112112

113-
private func makeRequest(route: String, method: String, headers: [String: String], params: [String: String?], body: Data?) throws -> URLRequest {
113+
private func makeRequest(route: String, method: String, headers: [String: String], params: [String: String?], body: Data?) throws(DescopeError) -> URLRequest {
114114
let url = try makeURL(route: route, params: params)
115115
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: defaultTimeout)
116116
request.httpMethod = method
@@ -121,7 +121,7 @@ class HTTPClient {
121121
return request
122122
}
123123

124-
private func makeURL(route: String, params: [String: String?]) throws -> URL {
124+
private func makeURL(route: String, params: [String: String?]) throws(DescopeError) -> URL {
125125
guard var url = URL(string: baseURL) else { throw DescopeError(httpError: .invalidRoute) }
126126
url.appendPathComponent(basePath, isDirectory: false)
127127
url.appendPathComponent(route, isDirectory: false)
@@ -146,7 +146,7 @@ extension JSONResponse {
146146
}
147147
}
148148

149-
private func decodeJSON<T: JSONResponse>(data: Data, response: HTTPURLResponse) throws -> T {
149+
private func decodeJSON<T: JSONResponse>(data: Data, response: HTTPURLResponse) throws(DescopeError) -> T {
150150
do {
151151
var val = try JSONDecoder().decode(T.self, from: data)
152152
try val.setValues(from: data, response: response)
@@ -158,7 +158,7 @@ private func decodeJSON<T: JSONResponse>(data: Data, response: HTTPURLResponse)
158158

159159
// JSON Request
160160

161-
private func encodeJSON(_ body: [String: Any?]) throws -> Data {
161+
private func encodeJSON(_ body: [String: Any?]) throws(DescopeError) -> Data {
162162
do {
163163
let compact = body.compacted()
164164
let data = try JSONSerialization.data(withJSONObject: compact, options: [])

ios/Classes/descope-swift-sdk/internal/others/Deprecated.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public extension DescopeFlow {
6767

6868
public extension SessionStorage.KeychainStore {
6969
@available(*, deprecated, message: "Use the init() initializer instead and set the accessibility property manually")
70-
public convenience init(accessibility: String) {
70+
convenience init(accessibility: String) {
7171
self.init()
7272
self.accessibility = accessibility
7373
}

ios/Classes/descope-swift-sdk/internal/others/Internal.swift

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,25 @@ extension String {
105105
}
106106
}
107107

108+
extension Task where Success == Never, Failure == Never {
109+
static func checkCancellation(throwing err: DescopeError) throws(DescopeError) {
110+
do {
111+
try checkCancellation()
112+
} catch {
113+
throw err
114+
}
115+
}
116+
117+
static func sleep(seconds: TimeInterval, throwing err: DescopeError) async throws(DescopeError) {
118+
do {
119+
let nanoseconds = UInt64(seconds * TimeInterval(NSEC_PER_SEC))
120+
try await Task.sleep(nanoseconds: nanoseconds)
121+
} catch {
122+
throw err
123+
}
124+
}
125+
}
126+
108127
class DefaultPresentationContextProvider: NSObject, ASWebAuthenticationPresentationContextProviding, ASAuthorizationControllerPresentationContextProviding {
109128
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
110129
return presentationAnchor
@@ -186,3 +205,79 @@ extension AuthenticationResponse: Codable {
186205
try values.encode(isFirstAuthentication, forKey: .isFirstAuthentication)
187206
}
188207
}
208+
209+
extension DescopeUser {
210+
struct SerializedUser: Codable, Equatable {
211+
var userId: String
212+
var loginIds: [String]
213+
var status: String?
214+
var createdAt: Date
215+
var email: String?
216+
var isVerifiedEmail: Bool
217+
var phone: String?
218+
var isVerifiedPhone: Bool
219+
var name: String?
220+
var givenName: String?
221+
var middleName: String?
222+
var familyName: String?
223+
var picture: URL?
224+
var authentication: Authentication?
225+
var authorization: Authorization?
226+
var customAttributes: String?
227+
var isUpdateRequired: Bool?
228+
}
229+
230+
static func serialize(_ user: DescopeUser) -> SerializedUser {
231+
var customAttributes = "{}"
232+
if JSONSerialization.isValidJSONObject(user.customAttributes), let data = try? JSONSerialization.data(withJSONObject: user.customAttributes), let value = String(bytes: data, encoding: .utf8) {
233+
customAttributes = value
234+
}
235+
236+
return SerializedUser(
237+
userId: user.userId,
238+
loginIds: user.loginIds,
239+
status: user.status.rawValue,
240+
createdAt: user.createdAt,
241+
email: user.email,
242+
isVerifiedEmail: user.isVerifiedEmail,
243+
phone: user.phone,
244+
isVerifiedPhone: user.isVerifiedPhone,
245+
name: user.name,
246+
givenName: user.givenName,
247+
middleName: user.middleName,
248+
familyName: user.familyName,
249+
picture: user.picture,
250+
authentication: user.authentication,
251+
authorization: user.authorization,
252+
customAttributes: customAttributes,
253+
isUpdateRequired: user.isUpdateRequired,
254+
)
255+
}
256+
257+
static func deserialize(_ user: SerializedUser) -> DescopeUser {
258+
var customAttributes: [String: Any] = [:]
259+
if let value = user.customAttributes, let json = try? JSONSerialization.jsonObject(with: Data(value.utf8)) {
260+
customAttributes = json as? [String: Any] ?? [:]
261+
}
262+
263+
return DescopeUser(
264+
userId: user.userId,
265+
loginIds: user.loginIds,
266+
status: Status(rawValue: user.status ?? "") ?? .enabled,
267+
createdAt: user.createdAt,
268+
email: user.email,
269+
isVerifiedEmail: user.isVerifiedEmail,
270+
phone: user.phone,
271+
isVerifiedPhone: user.isVerifiedPhone,
272+
name: user.name,
273+
givenName: user.givenName,
274+
middleName: user.middleName,
275+
familyName: user.familyName,
276+
picture: user.picture,
277+
authentication: user.authentication ?? Authentication(passkey: false, password: false, totp: false, oauth: [], sso: false, scim: false),
278+
authorization: user.authorization ?? Authorization(roles: [], ssoAppIds: []),
279+
customAttributes: customAttributes,
280+
isUpdateRequired: user.isUpdateRequired ?? true, // if the flag doesn't exist we've got old data without the new fields
281+
)
282+
}
283+
}

ios/Classes/descope-swift-sdk/internal/routes/AccessKey.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ final class AccessKey: DescopeAccessKey {
66
self.client = client
77
}
88

9-
func exchange(accessKey: String) async throws -> DescopeToken {
9+
func exchange(accessKey: String) async throws(DescopeError) -> DescopeToken {
1010
return try await client.accessKeyExchange(accessKey).convert()
1111
}
1212
}
1313

1414
private extension DescopeClient.AccessKeyExchangeResponse {
15-
func convert() throws -> DescopeToken {
15+
func convert() throws(DescopeError) -> DescopeToken {
1616
return try Token(jwt: sessionJwt)
1717
}
1818
}

ios/Classes/descope-swift-sdk/internal/routes/Auth.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,25 @@ final class Auth: DescopeAuth {
66
self.client = client
77
}
88

9-
func me(refreshJwt: String) async throws -> DescopeUser {
9+
func me(refreshJwt: String) async throws(DescopeError) -> DescopeUser {
1010
return try await client.me(refreshJwt: refreshJwt).convert()
1111
}
1212

13-
func tenants(dct: Bool, tenantIds: [String], refreshJwt: String) async throws -> [DescopeTenant] {
13+
func tenants(dct: Bool, tenantIds: [String], refreshJwt: String) async throws(DescopeError) -> [DescopeTenant] {
1414
return try await client.tenants(dct: dct, tenantIds: tenantIds, refreshJwt: refreshJwt).convert()
1515
}
1616

17-
func refreshSession(refreshJwt: String) async throws -> RefreshResponse {
17+
func refreshSession(refreshJwt: String) async throws(DescopeError) -> RefreshResponse {
1818
return try await client.refresh(refreshJwt: refreshJwt).convert()
1919
}
2020

21-
func migrateSession(externalToken: String) async throws -> AuthenticationResponse {
21+
func migrateSession(externalToken: String) async throws(DescopeError) -> AuthenticationResponse {
2222
let response: MigrateResponse = try await client.migrate(externalToken: externalToken).convert()
2323
let user = try await me(refreshJwt: response.refreshToken.jwt)
2424
return AuthenticationResponse(sessionToken: response.sessionToken, refreshToken: response.refreshToken, user: user, isFirstAuthentication: false)
2525
}
2626

27-
func revokeSessions(_ revoke: RevokeType, refreshJwt: String) async throws {
27+
func revokeSessions(_ revoke: RevokeType, refreshJwt: String) async throws(DescopeError) {
2828
try await client.logout(type: revoke, refreshJwt: refreshJwt)
2929
}
3030
}
@@ -35,7 +35,7 @@ private struct MigrateResponse {
3535
}
3636

3737
private extension DescopeClient.JWTResponse {
38-
func convert() throws -> RefreshResponse {
38+
func convert() throws(DescopeError) -> RefreshResponse {
3939
guard let sessionJwt, !sessionJwt.isEmpty else { throw DescopeError.decodeError.with(message: "Missing session JWT") }
4040
var refreshToken: DescopeToken?
4141
if let refreshJwt, !refreshJwt.isEmpty {
@@ -44,7 +44,7 @@ private extension DescopeClient.JWTResponse {
4444
return try RefreshResponse(sessionToken: Token(jwt: sessionJwt), refreshToken: refreshToken)
4545
}
4646

47-
func convert() throws -> MigrateResponse {
47+
func convert() throws(DescopeError) -> MigrateResponse {
4848
guard let sessionJwt, !sessionJwt.isEmpty else { throw DescopeError.decodeError.with(message: "Missing session JWT") }
4949
guard let refreshJwt, !refreshJwt.isEmpty else { throw DescopeError.decodeError.with(message: "Missing refresh JWT") }
5050
return try MigrateResponse(sessionToken: Token(jwt: sessionJwt), refreshToken: Token(jwt: refreshJwt))

0 commit comments

Comments
 (0)