1
1
/*
2
2
This source file is part of the Swift.org open source project
3
3
4
- Copyright (c) 2020 Apple Inc. and the Swift project authors
4
+ Copyright (c) 2020-2021 Apple Inc. and the Swift project authors
5
5
Licensed under Apache License v2.0 with Runtime Library Exception
6
6
7
7
See http://swift.org/LICENSE.txt for license information
@@ -103,7 +103,7 @@ public struct PackageCollections: PackageCollectionsProtocol {
103
103
}
104
104
let refreshResults = ThreadSafeArrayStore < Result < Model . Collection , Error > > ( )
105
105
sources. forEach { source in
106
- self . refreshCollectionFromSource ( source: source) { refreshResult in
106
+ self . refreshCollectionFromSource ( source: source, trustConfirmationProvider : nil ) { refreshResult in
107
107
refreshResults. append ( refreshResult)
108
108
if refreshResults. count == sources. count {
109
109
let errors = refreshResults. compactMap { $0. failure }
@@ -115,8 +115,16 @@ public struct PackageCollections: PackageCollectionsProtocol {
115
115
}
116
116
}
117
117
118
+ public func refreshCollection(
119
+ _ source: PackageCollectionsModel . CollectionSource ,
120
+ callback: @escaping ( Result < PackageCollectionsModel . Collection , Error > ) -> Void
121
+ ) {
122
+ self . refreshCollectionFromSource ( source: source, trustConfirmationProvider: nil , callback: callback)
123
+ }
124
+
118
125
public func addCollection( _ source: PackageCollectionsModel . CollectionSource ,
119
126
order: Int ? = nil ,
127
+ trustConfirmationProvider: ( ( PackageCollectionsModel . Collection , @escaping ( Bool ) -> Void ) -> Void ) ? = nil ,
120
128
callback: @escaping ( Result < PackageCollectionsModel . Collection , Error > ) -> Void ) {
121
129
if let errors = source. validate ( ) ? . errors ( ) {
122
130
return callback ( . failure( MultipleErrors ( errors) ) )
@@ -129,7 +137,7 @@ public struct PackageCollections: PackageCollectionsProtocol {
129
137
callback ( . failure( error) )
130
138
case . success:
131
139
// next try to fetch the collection from the network and store it locally so future operations dont need to access the network
132
- self . refreshCollectionFromSource ( source: source, order : order , callback: callback)
140
+ self . refreshCollectionFromSource ( source: source, trustConfirmationProvider : trustConfirmationProvider , callback: callback)
133
141
}
134
142
}
135
143
}
@@ -152,6 +160,18 @@ public struct PackageCollections: PackageCollectionsProtocol {
152
160
self . storage. sources. move ( source: source, to: order, callback: callback)
153
161
}
154
162
163
+ public func updateCollection( _ source: PackageCollectionsModel . CollectionSource ,
164
+ callback: @escaping ( Result < PackageCollectionsModel . Collection , Error > ) -> Void ) {
165
+ self . storage. sources. update ( source: source) { result in
166
+ switch result {
167
+ case . failure( let error) :
168
+ callback ( . failure( error) )
169
+ case . success:
170
+ self . refreshCollectionFromSource ( source: source, trustConfirmationProvider: nil , callback: callback)
171
+ }
172
+ }
173
+ }
174
+
155
175
// Returns information about a package collection.
156
176
// The collection is not required to be in the configured list.
157
177
// If not found locally (storage), the collection will be fetched from the source.
@@ -275,7 +295,7 @@ public struct PackageCollections: PackageCollectionsProtocol {
275
295
// Fetch the collection from the network and store it in local storage
276
296
// This helps avoid network access in normal operations
277
297
private func refreshCollectionFromSource( source: PackageCollectionsModel . CollectionSource ,
278
- order _ : Int ? = nil ,
298
+ trustConfirmationProvider : ( ( PackageCollectionsModel . Collection , @escaping ( Bool ) -> Void ) -> Void ) ? ,
279
299
callback: @escaping ( Result < Model . Collection , Error > ) -> Void ) {
280
300
if let errors = source. validate ( ) ? . errors ( ) {
281
301
return callback ( . failure( MultipleErrors ( errors) ) )
@@ -288,7 +308,52 @@ public struct PackageCollections: PackageCollectionsProtocol {
288
308
case . failure( let error) :
289
309
callback ( . failure( error) )
290
310
case . success( let collection) :
291
- self . storage. collections. put ( collection: collection, callback: callback)
311
+ // If collection is signed and signature is valid, save to storage. `provider.get`
312
+ // would have failed if signature were invalid.
313
+ if collection. isSigned {
314
+ return self . storage. collections. put ( collection: collection, callback: callback)
315
+ }
316
+
317
+ // If collection is not signed, check if it's trusted by user and prompt user if needed.
318
+ if let isTrusted = source. isTrusted {
319
+ if isTrusted {
320
+ return self . storage. collections. put ( collection: collection, callback: callback)
321
+ } else {
322
+ // Try to remove the untrusted collection (if previously saved) from storage before calling back
323
+ return self . storage. collections. remove ( identifier: collection. identifier) { _ in
324
+ callback ( . failure( PackageCollectionError . untrusted) )
325
+ }
326
+ }
327
+ }
328
+
329
+ // No user preference recorded, so we need to prompt if we can.
330
+ guard let trustConfirmationProvider = trustConfirmationProvider else {
331
+ // Try to remove the untrusted collection (if previously saved) from storage before calling back
332
+ return self . storage. collections. remove ( identifier: collection. identifier) { _ in
333
+ callback ( . failure( PackageCollectionError . trustConfirmationRequired) )
334
+ }
335
+ }
336
+
337
+ trustConfirmationProvider ( collection) { userTrusted in
338
+ var source = source
339
+ source. isTrusted = userTrusted
340
+ // Record user preference then save collection to storage
341
+ self . storage. sources. update ( source: source) { updateSourceResult in
342
+ switch updateSourceResult {
343
+ case . failure( let error) :
344
+ callback ( . failure( error) )
345
+ case . success:
346
+ if userTrusted {
347
+ self . storage. collections. put ( collection: collection, callback: callback)
348
+ } else {
349
+ // Try to remove the untrusted collection (if previously saved) from storage before calling back
350
+ return self . storage. collections. remove ( identifier: collection. identifier) { _ in
351
+ callback ( . failure( PackageCollectionError . untrusted) )
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }
292
357
}
293
358
}
294
359
}
0 commit comments