Skip to content
Closed
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
12 changes: 0 additions & 12 deletions flo/AuthMode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,3 @@ enum AuthMode: String, Codable {
case standard
case iap
}

struct IAPAuthInfo: Codable {
let jwtAssertion: String
let userEmail: String?
let userId: String?

init(jwtAssertion: String, userEmail: String? = nil, userId: String? = nil) {
self.jwtAssertion = jwtAssertion
self.userEmail = userEmail
self.userId = userId
}
}
75 changes: 8 additions & 67 deletions flo/AuthViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ class AuthViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false

@Published var authMode: AuthMode = .standard
@Published var iapJwtAssertion: String = ""
@Published var useIAPAuth: Bool = false

static let shared = AuthViewModel()

Expand All @@ -56,18 +54,20 @@ class AuthViewModel: ObservableObject {

authMode = AuthService.shared.getAuthMode()

if UserDefaultsManager.saveLoginInfo {
if authMode == .iap {
user = UserAuth(
id: data.id, username: data.username, name: data.name, isAdmin: data.isAdmin,
lastFMApiKey: data.lastFMApiKey
)
isLoggedIn = true
} else if UserDefaultsManager.saveLoginInfo {
do {
password = try KeychainManager.getAuthPassword() ?? ""
} catch {
print("Error loading password from Keychain: \(error)")
}

if authMode == .iap, let iapInfo = AuthService.shared.getIAPAuthInfo() {
loginWithIAP(jwtAssertion: iapInfo.jwtAssertion)
} else {
login()
}
login()
} else {
user = UserAuth(
id: data.id, username: data.username, name: data.name, isAdmin: data.isAdmin,
Expand Down Expand Up @@ -135,9 +135,7 @@ class AuthViewModel: ObservableObject {
destroySavedPassword()

if authMode == .iap {
try? KeychainManager.removeIAPAuthInfo()
try? KeychainManager.removeAuthMode()
AuthService.shared.clearIAPAuthInfo()
}

UserDefaultsManager.removeObject(key: UserDefaultsKeys.serverURL)
Expand Down Expand Up @@ -184,61 +182,4 @@ class AuthViewModel: ObservableObject {
}
}

func loginWithIAP(jwtAssertion: String? = nil) {
isSubmitting = true

let jwt = jwtAssertion ?? iapJwtAssertion

guard !jwt.isEmpty else {
DispatchQueue.main.async {
self.isSubmitting = false
self.alertMessage = "JWT assertion is required for IAP authentication"
self.showAlert = true
}
return
}

AuthService.shared.loginWithIAP(serverUrl: serverUrl, jwtAssertion: jwt) { result in
switch result {
case .success(let data):
self.persistAuthData(data)

self.authMode = .iap

if UserDefaultsManager.saveLoginInfo {
self.destroySavedPassword()
}

DispatchQueue.main.async {
self.isSubmitting = false
self.isLoggedIn = true
self.iapJwtAssertion = ""
self.serverUrl = ""
}

case .failure(let error):
DispatchQueue.main.async {
self.isSubmitting = false

switch error {
case .server(let message):
self.alertMessage = message

case .unknown:
self.alertMessage = "Unknown error occurred during IAP authentication"
}

self.showAlert = true
}
}
}
}

func toggleAuthMode() {
useIAPAuth.toggle()
}

func isUsingIAPAuth() -> Bool {
return authMode == .iap
}
}
8 changes: 7 additions & 1 deletion flo/PlayerViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,13 @@ class PlayerViewModel: ObservableObject {

self._playFromLocal = audioURL.isFileURL

self.playerItem = AVPlayerItem(url: audioURL)
if !audioURL.isFileURL, AuthService.shared.getAuthMode() == .iap {
let cookies = HTTPCookieStorage.shared.cookies(for: audioURL) ?? []
let asset = AVURLAsset(url: audioURL, options: [AVURLAssetHTTPCookiesKey: cookies])
self.playerItem = AVPlayerItem(asset: asset)
} else {
self.playerItem = AVPlayerItem(url: audioURL)
}
self.player?.replaceCurrentItem(with: self.playerItem)

let duration = CMTime(
Expand Down
10 changes: 10 additions & 0 deletions flo/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@
},
"Advanced Settings" : {
"comment" : "A toggle label for advanced settings in the IAP login view.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand Down Expand Up @@ -699,6 +700,7 @@
},
"Authentication Token Cookie Name" : {
"comment" : "A description of the authentication token cookie name setting.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand All @@ -711,6 +713,7 @@
},
"Authentication Token Header Name" : {
"comment" : "A label displayed above a text field that lets the user specify the name of the HTTP header containing their JWT token.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand Down Expand Up @@ -1198,6 +1201,7 @@
},
"e.g., _oauth2_proxy, KEYCLOAK_IDENTITY" : {
"comment" : "A placeholder text for the \"Authentication Token Cookie Name\" field in the IAP login view.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand All @@ -1210,6 +1214,7 @@
},
"e.g., username, user, preferred_username" : {
"comment" : "A placeholder text for the \"Username Cookie Name\" field in the advanced settings of the IAP login view.",
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
Expand All @@ -1221,6 +1226,7 @@
},
"e.g., x-auth-request-access-token" : {
"comment" : "A placeholder text for the authentication token header name field in the advanced settings of the IAP login view.",
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
Expand Down Expand Up @@ -3308,6 +3314,7 @@
},
"The cookie containing your session token (leave empty for auto-detection)" : {
"comment" : "A description of the purpose of the \"Authentication Token Cookie Name\" field.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand All @@ -3320,6 +3327,7 @@
},
"The cookie containing your username (defaults to 'username')" : {
"comment" : "A description of the purpose of the \"Username Cookie Name\" setting in the IAP login view.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand Down Expand Up @@ -3354,6 +3362,7 @@
},
"The HTTP header containing your JWT token (leave empty for auto-detection)" : {
"comment" : "A description of what the \"Authentication Token Header Name\" field is for.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand Down Expand Up @@ -3743,6 +3752,7 @@
},
"Username Cookie Name" : {
"comment" : "A label for the username cookie name field in the IAP login view.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"de" : {
Expand Down
2 changes: 1 addition & 1 deletion flo/Shared/Models/UserAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ struct UserAuth: Codable {
self.lastFMApiKey = try container.decodeIfPresent(String.self, forKey: .lastFMApiKey) ?? ""
self.subsonicSalt = try container.decode(String.self, forKey: .subsonicSalt)
self.subsonicToken = try container.decode(String.self, forKey: .subsonicToken)
self.token = try container.decode(String.self, forKey: .token)
self.token = try container.decodeIfPresent(String.self, forKey: .token) ?? ""
}
}
24 changes: 0 additions & 24 deletions flo/Shared/Services/APIManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,30 +172,6 @@ extension APIManager {
completion(response)
}
}

func loginWithIAP<T: Decodable>(
endpoint: String, parameters: Parameters?, jwtAssertion: String,
completion: @escaping (DataResponse<T, AFError>) -> Void
) {
let headers: HTTPHeaders = [
"X-Goog-IAP-JWT-Assertion": jwtAssertion
]

session.request(
endpoint,
method: .post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: headers,
requestModifier: { request in
request.timeoutInterval = 10
}
)
.validate(statusCode: 200..<500)
.responseDecodable(of: T.self) { response in
completion(response)
}
}

func externalRequest<T: Decodable>(
url: String,
Expand Down
Loading