Skip to content

Commit

Permalink
[fix/permissions] Limit action availability based on permissions (#632)
Browse files Browse the repository at this point in the history
* - ClientRootViewController: do not add dot to the end of the short connection status description if it already has one
- UIImageView+Thumbnails: fix retain loop, leading to leaking an OCCore - and all possible issues relating to that

* - Update to latest SDK

* - Update SDK and adapt ProgressSummarizer for new event type

* - Fix core-stop-blocking share reload query retain loop via SDK update

* - add permission checks to CreateFolderAction, DeleteAction, DocumentEditingAction, MoveAction, RenameAction, ScanAction and UploadBaseAction, so they are unavailable if permissions aren't sufficient for their usage
- add alert to inform the user that no actions are available in cases where no actions are available for a folder and the user presses the folder action "+" button

* - Update SDK

* fixed QA finding (1) #623

* Fix for QA issue (2)

Media upload settings shall not allow selection of the upload folder which lacks required Permissions

* #623 QA finding (6) allow Markup it at least one permission is available and restrict save actions to available permissions

* - address issue (1) using ActionContext.query.rootItem

* OCCore+Extension.swift:
- remove items from OCShareQueries where they are not used by the core to avoid warnings in the log
- add option for partial matches to sharesSharedWithMe() via allowPartialMatch option

PublicLinkTableViewController.swift:
- take advantage of allowPartialMatch option
- determine share nested the deepest to determine permissions (fixes finding 84) in #632

* - Update SDK

* - make move action available for directories with .move or .delete permission (as documented in #632 (comment) )

* - Fix finding (3) in #632 via SDK update

Co-authored-by: Matthias Hühne <[email protected]>
  • Loading branch information
felix-schwarz and hosy authored Mar 3, 2020
1 parent 88df01d commit f9a0201
Show file tree
Hide file tree
Showing 17 changed files with 89 additions and 26 deletions.
2 changes: 1 addition & 1 deletion ios-sdk
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class CreateFolderAction : Action {
return .none
}

if forContext.items.first?.permissions.contains(.createFolder) == false {
return .none
}

return .first
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class DeleteAction : Action {
}
}

if forContext.items.filter({return $0.isRoot}).count > 0 {
if forContext.items.filter({return $0.isRoot || !$0.permissions.contains(.delete)}).count > 0 {
return .none

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class DocumentEditingAction : Action {

// MARK: - Extension matching
override class func applicablePosition(forContext: ActionContext) -> ActionPosition {
if forContext.items.count == 1, forContext.items.contains(where: {$0.type == .file}) {
if let core = forContext.core, forContext.items.count == 1, forContext.items.contains(where: {$0.type == .file && ($0.permissions.contains(.writable) || $0.parentItem(from: core)? .permissions.contains(.createFile) == true)}) {
if let item = forContext.items.first, let mimeType = item.mimeType {
if supportedMimeTypes.filter({
if mimeType.contains($0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ class DuplicateAction : Action {

// MARK: - Extension matching
override class func applicablePosition(forContext: ActionContext) -> ActionPosition {
if forContext.items.filter({return $0.isRoot}).count > 0 {
if let rootItem = forContext.query?.rootItem, !rootItem.permissions.contains(.createFile) || !rootItem.permissions.contains(.createFolder) {
return .none
}

if forContext.items.filter({return $0.isRoot}).count > 0 {
return .none
}

return .middle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class MoveAction : Action {

// MARK: - Extension matching
override class func applicablePosition(forContext: ActionContext) -> ActionPosition {
if forContext.items.filter({return $0.isRoot}).count > 0 {
if forContext.items.filter({return $0.isRoot || (!$0.permissions.contains(.move) && !$0.permissions.contains(.delete))}).count > 0 {
return .none

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class RenameAction : Action {
if forContext.items.count > 1 {
return .none
}
if forContext.items.filter({return $0.isRoot}).count > 0 {
if forContext.items.filter({return $0.isRoot || !$0.permissions.contains(.rename)}).count > 0 {
return .none

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class UploadBaseAction: Action {
return .none
}

if forContext.items.first?.permissions.contains(.createFile) == false {
return .none
}

return .middle
}

Expand Down
21 changes: 12 additions & 9 deletions ownCloud/Client/Actions/EditDocumentViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,20 @@ class EditDocumentViewController: QLPreviewController, Themeable {
message: nil,
preferredStyle: .alert)

alertController.addAction(UIAlertAction(title: "Overwrite original".localized, style: .default, handler: { (_) in
self.savingMode = .updateContents
if item.permissions.contains(.writable) {
alertController.addAction(UIAlertAction(title: "Overwrite original".localized, style: .default, handler: { (_) in
self.savingMode = .updateContents

completion?(.updateContents)
}))

alertController.addAction(UIAlertAction(title: "Save as copy".localized, style: .default, handler: { (_) in
self.savingMode = .createCopy
completion?(.updateContents)
}))
}
if let core = core, item.parentItem(from: core)?.permissions.contains(.createFile) == true {
alertController.addAction(UIAlertAction(title: "Save as copy".localized, style: .default, handler: { (_) in
self.savingMode = .createCopy

completion?(.createCopy)
}))
completion?(.createCopy)
}))
}

alertController.addAction(UIAlertAction(title: "Discard changes".localized, style: .destructive, handler: { (_) in
self.savingMode = .disabled
Expand Down
4 changes: 4 additions & 0 deletions ownCloud/Client/Actions/Scanner/ScanAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class ScanAction: Action, VNDocumentCameraViewControllerDelegate {
return .none
}

if forContext.items.first?.permissions.contains(.createFile) == false {
return .none
}

if #available(iOS 13.0, *) {
return .middle
} else {
Expand Down
13 changes: 12 additions & 1 deletion ownCloud/Client/ClientQueryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,6 @@ class ClientQueryViewController: QueryFileListTableViewController, UIDropInterac
}

@objc func plusBarButtonPressed(_ sender: UIBarButtonItem) {

let controller = ThemedAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

// Actions for folderAction
Expand All @@ -528,6 +527,17 @@ class ClientQueryViewController: QueryFileListTableViewController, UIDropInterac

let actions = Action.sortedApplicableActions(for: actionContext)

if actions.count == 0 {
// Handle case of no actions
let alert = ThemedAlertController(title: "No actions available".localized, message: "No actions are available for this folder, possibly because of missing permissions.".localized, preferredStyle: .alert)

alert.addAction(UIAlertAction(title: "OK".localized, style: .default))

self.present(alert, animated: true)

return
}

for action in actions {
action.progressHandler = makeActionProgressHandler()

Expand All @@ -544,6 +554,7 @@ class ClientQueryViewController: QueryFileListTableViewController, UIDropInterac
if let popoverController = controller.popoverPresentationController {
popoverController.barButtonItem = sender
}

self.present(controller, animated: true)
}

Expand Down
21 changes: 19 additions & 2 deletions ownCloud/Client/Sharing/PublicLinkTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,29 @@ class PublicLinkTableViewController: SharingTableViewController {
if item.isSharedWithUser {
core.sharesSharedWithMe(for: item, initialPopulationHandler: { shares in
OnMainThread {
if let share = shares.filter({ $0.itemPath == path}).first {
var deepestShare : OCShare?

for share in shares {
if share.itemPath == path {
deepestShare = share
break
} else {
if path.hasPrefix(share.itemPath) {
if deepestShare == nil {
deepestShare = share
} else if let deepestShareItemPath = deepestShare?.itemPath, share.itemPath.count > deepestShareItemPath.count {
deepestShare = share
}
}
}
}

if let share = deepestShare {
permissions = share.permissions
createLink(for: path, with: permissions!)
}
}
})
}, allowPartialMatch: true)
} else {
permissions = [.create, .read]
createLink(for: path, with: permissions!)
Expand Down
Binary file modified ownCloud/Resources/de.lproj/Localizable.strings
Binary file not shown.
4 changes: 4 additions & 0 deletions ownCloud/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@

"Preparing…" = "Preparing…";

"No actions available" = "No actions available";
"No actions are available for this folder, possibly because of missing permissions." = "No actions are available for this folder, possibly because of missing permissions.";

/* Directory Picker Messages */
"Move here" = "Move here";

Expand Down Expand Up @@ -312,6 +315,7 @@
"Importing from photo library" = "Importing from photo library";
"Media import" = "Media import";
"%@ of %@" = "%@ of %@";
"Selected folder lacks file creation permission" = "Selected folder lacks file creation permission";

/* Scan */
"Scan" = "Scan";
Expand Down
Binary file modified ownCloud/Resources/ru.lproj/Localizable.strings
Binary file not shown.
9 changes: 5 additions & 4 deletions ownCloud/SDK Extensions/OCCore+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ extension OCCore {
start(shareQuery)
}

if let shareQuery = OCShareQuery(scope: .sharedWithUser, item: item) {
if let shareQuery = OCShareQuery(scope: .sharedWithUser, item: nil) {
dispatchGroup.enter()

shareQuery.initialPopulationHandler = { [weak self] query in
Expand Down Expand Up @@ -67,11 +67,12 @@ extension OCCore {
})
}

@discardableResult func sharesSharedWithMe(for item: OCItem, initialPopulationHandler: @escaping (_ shares: [OCShare]) -> Void, keepRunning: Bool = false) -> OCShareQuery? {
if let shareQuery = OCShareQuery(scope: .sharedWithUser, item: item) {
@discardableResult func sharesSharedWithMe(for item: OCItem, initialPopulationHandler: @escaping (_ shares: [OCShare]) -> Void, allowPartialMatch : Bool = false, keepRunning: Bool = false) -> OCShareQuery? {
if let shareQuery = OCShareQuery(scope: .sharedWithUser, item: nil) {
shareQuery.initialPopulationHandler = { [weak self] query in
let shares = query.queryResults.filter({ (share) -> Bool in
return share.itemPath == item.path
return (share.itemPath == item.path) ||
(allowPartialMatch && (item.path?.hasPrefix(share.itemPath) == true))
})
initialPopulationHandler(shares)

Expand Down
20 changes: 16 additions & 4 deletions ownCloud/Settings/MediaUploadSettingsSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -354,12 +354,24 @@ class MediaUploadSettingsSection: SettingsSection {

OnMainThread {
let directoryPickerViewController = ClientDirectoryPickerViewController(core: core, path: "/", selectButtonTitle: "Select Upload Path".localized, avoidConflictsWith: [], choiceHandler: { (selectedDirectory) in
if selectedDirectory != nil {
self?.userDefaults.instantUploadPath = selectedDirectory?.path
}
var success = false
OCCoreManager.shared.returnCore(for: bookmark, completionHandler: nil)

completion(selectedDirectory != nil)
if let directory = selectedDirectory {
if directory.permissions.contains(.createFile) {
print("Can create files")
self?.userDefaults.instantUploadPath = selectedDirectory?.path
success = true
} else {
OnMainThread {
let alert = ThemedAlertController(title: "Missing permissions".localized, message: "This permission is needed to upload photos and videos from your photo library.".localized, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK".localized, style: .default, handler: nil))
self?.viewController?.present(alert, animated: true, completion: nil)
}
}
}

completion(success)
})
navigationController?.pushViewController(directoryPickerViewController, animated: true)
}
Expand Down

0 comments on commit f9a0201

Please sign in to comment.