Skip to content

Commit f00ba11

Browse files
authored
Fix LCP localization fallback and add Keychain clear API (#722)
1 parent d1a9ada commit f00ba11

File tree

186 files changed

+1934
-1452
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

186 files changed

+1934
-1452
lines changed

BuildTools/Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

BuildTools/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ let package = Package(
1111
name: "BuildTools",
1212
platforms: [.macOS(.v10_11)],
1313
dependencies: [
14-
.package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.51.6"),
14+
.package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.59.1"),
1515
],
1616
targets: [.target(name: "BuildTools", path: "")]
1717
)

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// swift-tools-version:5.10
22
//
3-
// Copyright 2025 Readium Foundation. All rights reserved.
3+
// Copyright 2026 Readium Foundation. All rights reserved.
44
// Use of this source code is governed by the BSD-style license
55
// available in the top-level LICENSE file of the project.
66
//

Sources/Adapters/LCPSQLite/SQLiteLCPPassphraseRepository.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,17 @@ public class LCPSQLitePassphraseRepository: LCPPassphraseRepository, Loggable {
3333
public func passphrase(for licenseID: LicenseDocument.ID) async throws -> LCPPassphraseHash? {
3434
try logAndRethrow {
3535
try db.prepare(transactions.select(passphrase)
36-
.filter(self.licenseId == licenseID)
37-
)
38-
.compactMap { try $0.get(passphrase) }
39-
.first
36+
.filter(self.licenseId == licenseID))
37+
.compactMap { try $0.get(passphrase) }
38+
.first
4039
}
4140
}
4241

4342
public func passphrasesMatching(userID: User.ID?, provider: LicenseDocument.Provider) async throws -> [LCPPassphraseHash] {
4443
try logAndRethrow {
4544
try db.prepare(transactions.select(passphrase)
46-
.filter(self.userId == userID && self.provider == provider)
47-
)
48-
.compactMap { try $0.get(passphrase) }
45+
.filter(self.userId == userID && self.provider == provider))
46+
.compactMap { try $0.get(passphrase) }
4947
}
5048
}
5149

Sources/Internal/Keychain.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public final class Keychain: Sendable {
4848
/// - Parameters:
4949
/// - data: The data to save.
5050
/// - key: The account identifier.
51-
public func save(data: Data, forKey key: String) throws (KeychainError) {
51+
public func save(data: Data, forKey key: String) throws(KeychainError) {
5252
var query = baseQuery(forKey: key, forAdding: true)
5353
query[kSecValueData as String] = data
5454

@@ -63,7 +63,7 @@ public final class Keychain: Sendable {
6363
///
6464
/// - Parameter key: The account identifier.
6565
/// - Returns: The data if found, or `nil` if no item exists with this key.
66-
public func load(forKey key: String) throws (KeychainError) -> Data? {
66+
public func load(forKey key: String) throws(KeychainError) -> Data? {
6767
var query = baseQuery(forKey: key, forAdding: false)
6868
query[kSecReturnData as String] = true
6969
query[kSecMatchLimit as String] = kSecMatchLimitOne
@@ -91,7 +91,7 @@ public final class Keychain: Sendable {
9191
/// - Parameters:
9292
/// - data: The new data to save.
9393
/// - key: The account identifier.
94-
public func update(data: Data, forKey key: String) throws (KeychainError) {
94+
public func update(data: Data, forKey key: String) throws(KeychainError) {
9595
let query = baseQuery(forKey: key, forAdding: false)
9696
let attributesToUpdate: [String: Any] = [
9797
kSecValueData as String: data,
@@ -107,7 +107,7 @@ public final class Keychain: Sendable {
107107
/// Deletes an item from the Keychain for the specified key.
108108
///
109109
/// - Parameter key: The account identifier.
110-
public func delete(forKey key: String) throws (KeychainError) {
110+
public func delete(forKey key: String) throws(KeychainError) {
111111
let query = baseQuery(forKey: key, forAdding: false)
112112
let status = SecItemDelete(query as CFDictionary)
113113

@@ -118,7 +118,7 @@ public final class Keychain: Sendable {
118118
}
119119

120120
/// Deletes all items for this service from the Keychain.
121-
public func deleteAll() throws (KeychainError) {
121+
public func deleteAll() throws(KeychainError) {
122122
let query: [String: Any] = [
123123
kSecClass as String: kSecClassGenericPassword,
124124
kSecAttrService as String: serviceName,
@@ -134,7 +134,7 @@ public final class Keychain: Sendable {
134134
/// Returns all account identifiers (keys) stored for this service.
135135
///
136136
/// - Returns: An array of account identifiers.
137-
public func allKeys() throws (KeychainError) -> [String] {
137+
public func allKeys() throws(KeychainError) -> [String] {
138138
let query: [String: Any] = [
139139
kSecClass as String: kSecClassGenericPassword,
140140
kSecAttrService as String: serviceName,
@@ -165,7 +165,7 @@ public final class Keychain: Sendable {
165165
///
166166
/// - Returns: A dictionary where keys are account identifiers and values are
167167
/// the stored data.
168-
public func allItems() throws (KeychainError) -> [String: Data] {
168+
public func allItems() throws(KeychainError) -> [String: Data] {
169169
let query: [String: Any] = [
170170
kSecClass as String: kSecClassGenericPassword,
171171
kSecAttrService as String: serviceName,

Sources/Internal/UTI.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@ public struct UTI {
4141
self.init(type: type)
4242
}
4343

44-
public var name: String? { type.localizedDescription }
44+
public var name: String? {
45+
type.localizedDescription
46+
}
4547

46-
public var string: String { type.identifier }
48+
public var string: String {
49+
type.identifier
50+
}
4751

4852
/// Returns the preferred tag for this `UTI`, with the given type `tagClass`.
4953
public func preferredTag(withClass tagClass: TagClass) -> String? {

Sources/LCP/Authentications/LCPAuthenticating.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,4 @@ public struct LCPAuthenticatedLicense {
6868

6969
/// License Document being opened.
7070
public let document: LicenseDocument
71-
72-
init(document: LicenseDocument) {
73-
self.document = document
74-
}
7571
}

Sources/LCP/Authentications/LCPDialog.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public struct LCPDialog: View {
5858
}
5959
}
6060

61-
public var id: LCPDialog { self }
61+
public var id: LCPDialog {
62+
self
63+
}
6264

6365
private let hint: String?
6466
private let errorMessage: ErrorMessage?
@@ -137,7 +139,7 @@ public struct LCPDialog: View {
137139
.navigationViewStyle(.stack)
138140
}
139141

140-
@ViewBuilder private var header: some View {
142+
private var header: some View {
141143
Section {
142144
HStack {
143145
Spacer()
@@ -168,7 +170,7 @@ public struct LCPDialog: View {
168170
.font(.callout)
169171
}
170172

171-
@ViewBuilder private var input: some View {
173+
private var input: some View {
172174
Section {
173175
VStack(alignment: .leading, spacing: 8) {
174176
TextField(text: $passphrase) {

Sources/LCP/Content Protection/LCPContentProtection.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ final class LCPContentProtection: ContentProtection, Loggable {
5656
return await asset.resource.readAsLCPL()
5757
.mapError { .reading($0) }
5858
.asyncFlatMap { licenseDocument in
59-
6059
await assetRetriever.retrieve(link: licenseDocument.publicationLink)
6160
.flatMap { publicationAsset in
6261
switch publicationAsset {

Sources/LCP/LCPError.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,50 +81,50 @@ public enum StatusError: Error {
8181

8282
/// Errors while renewing a loan.
8383
public enum RenewError: Error {
84-
// Your publication could not be renewed properly.
84+
/// Your publication could not be renewed properly.
8585
case renewFailed
86-
// Incorrect renewal period, your publication could not be renewed.
86+
/// Incorrect renewal period, your publication could not be renewed.
8787
case invalidRenewalPeriod(maxRenewDate: Date?)
88-
// An unexpected error has occurred on the licensing server.
88+
/// An unexpected error has occurred on the licensing server.
8989
case unexpectedServerError(HTTPError)
9090
}
9191

9292
/// Errors while returning a loan.
9393
public enum ReturnError: Error {
94-
// Your publication could not be returned properly.
94+
/// Your publication could not be returned properly.
9595
case returnFailed
96-
// Your publication has already been returned before or is expired.
96+
/// Your publication has already been returned before or is expired.
9797
case alreadyReturnedOrExpired
98-
// An unexpected error has occurred on the licensing server.
98+
/// An unexpected error has occurred on the licensing server.
9999
case unexpectedServerError(HTTPError)
100100
}
101101

102102
/// Errors while parsing the License or Status JSON Documents.
103103
public enum ParsingError: Error {
104-
// The JSON is malformed and can't be parsed.
104+
/// The JSON is malformed and can't be parsed.
105105
case malformedJSON
106-
// The JSON is not representing a valid License Document.
106+
/// The JSON is not representing a valid License Document.
107107
case licenseDocument
108-
// The JSON is not representing a valid Status Document.
108+
/// The JSON is not representing a valid Status Document.
109109
case statusDocument
110-
// Invalid Link.
110+
/// Invalid Link.
111111
case link
112-
// Invalid Encryption.
112+
/// Invalid Encryption.
113113
case encryption
114-
// Invalid License Document Signature.
114+
/// Invalid License Document Signature.
115115
case signature
116-
// Invalid URL for link with rel %@.
116+
/// Invalid URL for link with rel %@.
117117
case url(rel: String)
118118
}
119119

120120
/// Errors while reading or writing a LCP container (LCPL, EPUB, LCPDF, etc.)
121121
public enum ContainerError: Error {
122-
// Can't access the container, it's format is wrong.
122+
/// Can't access the container, it's format is wrong.
123123
case openFailed(Error?)
124-
// The file at given relative path is not found in the Container.
124+
/// The file at given relative path is not found in the Container.
125125
case fileNotFound(String)
126-
// Can't read the file at given relative path in the Container.
126+
/// Can't read the file at given relative path in the Container.
127127
case readFailed(path: String)
128-
// Can't write the file at given relative path in the Container.
128+
/// Can't write the file at given relative path in the Container.
129129
case writeFailed(path: String)
130130
}

0 commit comments

Comments
 (0)