Skip to content

Commit 3f5acbf

Browse files
committed
feat: support receive encrypted folders
Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
1 parent 8389395 commit 3f5acbf

File tree

7 files changed

+413
-94
lines changed

7 files changed

+413
-94
lines changed

Localizable.xcstrings

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24884,6 +24884,52 @@
2488424884
}
2488524885
}
2488624886
},
24887+
"Receive encrypted" : {
24888+
"localizations" : {
24889+
"de" : {
24890+
"stringUnit" : {
24891+
"state" : "translated",
24892+
"value" : "Verschlüsselt empfangen"
24893+
}
24894+
},
24895+
"es" : {
24896+
"stringUnit" : {
24897+
"state" : "translated",
24898+
"value" : "Recibir cifrado"
24899+
}
24900+
},
24901+
"it" : {
24902+
"stringUnit" : {
24903+
"state" : "translated",
24904+
"value" : "Ricevi crittografato"
24905+
}
24906+
},
24907+
"ja" : {
24908+
"stringUnit" : {
24909+
"state" : "translated",
24910+
"value" : "暗号化を受信"
24911+
}
24912+
},
24913+
"nl" : {
24914+
"stringUnit" : {
24915+
"state" : "translated",
24916+
"value" : "Ontvang versleuteld"
24917+
}
24918+
},
24919+
"uk" : {
24920+
"stringUnit" : {
24921+
"state" : "translated",
24922+
"value" : "Отримати зашифровано"
24923+
}
24924+
},
24925+
"zh-Hans" : {
24926+
"stringUnit" : {
24927+
"state" : "translated",
24928+
"value" : "接收加密"
24929+
}
24930+
}
24931+
}
24932+
},
2488724933
"Receive only" : {
2488824934
"localizations" : {
2488924935
"de" : {
@@ -33850,6 +33896,52 @@
3385033896
}
3385133897
}
3385233898
},
33899+
"The files in this folder cannot be shown" : {
33900+
"localizations" : {
33901+
"de" : {
33902+
"stringUnit" : {
33903+
"state" : "translated",
33904+
"value" : "Die Dateien in diesem Ordner können nicht angezeigt werden"
33905+
}
33906+
},
33907+
"es" : {
33908+
"stringUnit" : {
33909+
"state" : "translated",
33910+
"value" : "Los archivos de esta carpeta no se pueden mostrar"
33911+
}
33912+
},
33913+
"it" : {
33914+
"stringUnit" : {
33915+
"state" : "translated",
33916+
"value" : "I file in questa cartella non possono essere visualizzati"
33917+
}
33918+
},
33919+
"ja" : {
33920+
"stringUnit" : {
33921+
"state" : "translated",
33922+
"value" : "このフォルダのファイルは表示できません"
33923+
}
33924+
},
33925+
"nl" : {
33926+
"stringUnit" : {
33927+
"state" : "translated",
33928+
"value" : "De bestanden in deze map kunnen niet worden getoond"
33929+
}
33930+
},
33931+
"uk" : {
33932+
"stringUnit" : {
33933+
"state" : "translated",
33934+
"value" : "Файли в цій папці не можуть бути відображені"
33935+
}
33936+
},
33937+
"zh-Hans" : {
33938+
"stringUnit" : {
33939+
"state" : "translated",
33940+
"value" : "此文件夹中的文件无法显示"
33941+
}
33942+
}
33943+
}
33944+
},
3385333945
"The files to download" : {
3385433946
"localizations" : {
3385533947
"de" : {
@@ -36070,6 +36162,52 @@
3607036162
}
3607136163
}
3607236164
},
36165+
"This device will receive encrypted files from other devices. The files are stored on this device, but cannot be accessed from this device." : {
36166+
"localizations" : {
36167+
"de" : {
36168+
"stringUnit" : {
36169+
"state" : "translated",
36170+
"value" : "Dieses Gerät empfängt verschlüsselte Dateien von anderen Geräten. Die Dateien werden auf diesem Gerät gespeichert, können jedoch von diesem Gerät aus nicht darauf zugegriffen werden."
36171+
}
36172+
},
36173+
"es" : {
36174+
"stringUnit" : {
36175+
"state" : "translated",
36176+
"value" : "Este dispositivo recibirá archivos cifrados de otros dispositivos. Los archivos se almacenan en este dispositivo, pero no se pueden acceder desde este dispositivo."
36177+
}
36178+
},
36179+
"it" : {
36180+
"stringUnit" : {
36181+
"state" : "translated",
36182+
"value" : "Questo dispositivo riceverà file crittografati da altri dispositivi. I file sono archiviati su questo dispositivo, ma non possono essere accessibili da questo dispositivo."
36183+
}
36184+
},
36185+
"ja" : {
36186+
"stringUnit" : {
36187+
"state" : "translated",
36188+
"value" : "このデバイスは、他のデバイスから暗号化されたファイルを受信します。ファイルはこのデバイスに保存されますが、このデバイスからはアクセスできません。"
36189+
}
36190+
},
36191+
"nl" : {
36192+
"stringUnit" : {
36193+
"state" : "translated",
36194+
"value" : "Dit apparaat ontvangt versleutelde bestanden van andere apparaten. De bestanden worden op dit apparaat opgeslagen, maar zijn niet toegankelijk vanaf dit apparaat."
36195+
}
36196+
},
36197+
"uk" : {
36198+
"stringUnit" : {
36199+
"state" : "translated",
36200+
"value" : "Цей пристрій отримуватиме зашифровані файли з інших пристроїв. Файли зберігаються на цьому пристрої, але не можуть бути доступними з цього пристрою."
36201+
}
36202+
},
36203+
"zh-Hans" : {
36204+
"stringUnit" : {
36205+
"state" : "translated",
36206+
"value" : "此设备将从其他设备接收加密文件。文件存储在此设备上,但无法从此设备访问。"
36207+
}
36208+
}
36209+
}
36210+
},
3607336211
"This device's identifier" : {
3607436212
"localizations" : {
3607536213
"de" : {
@@ -36484,6 +36622,52 @@
3648436622
}
3648536623
}
3648636624
},
36625+
"This folder is receiving encrypted files. While these files are stored on this device, they cannot be accessed from this device." : {
36626+
"localizations" : {
36627+
"de" : {
36628+
"stringUnit" : {
36629+
"state" : "translated",
36630+
"value" : "Dieser Ordner empfängt verschlüsselte Dateien. Solange diese Dateien auf diesem Gerät gespeichert sind, können sie nicht von diesem Gerät aus zugegriffen werden."
36631+
}
36632+
},
36633+
"es" : {
36634+
"stringUnit" : {
36635+
"state" : "translated",
36636+
"value" : "Esta carpeta está recibiendo archivos cifrados. Mientras estos archivos estén almacenados en este dispositivo, no se podrán acceder desde este dispositivo."
36637+
}
36638+
},
36639+
"it" : {
36640+
"stringUnit" : {
36641+
"state" : "translated",
36642+
"value" : "Questa cartella riceve file crittografati. Finché questi file sono archiviati su questo dispositivo, non possono essere accessibili da questo dispositivo."
36643+
}
36644+
},
36645+
"ja" : {
36646+
"stringUnit" : {
36647+
"state" : "translated",
36648+
"value" : "このフォルダは暗号化されたファイルを受信しています。これらのファイルはこのデバイスに保存されている間、このデバイスからアクセスすることはできません。"
36649+
}
36650+
},
36651+
"nl" : {
36652+
"stringUnit" : {
36653+
"state" : "translated",
36654+
"value" : "Deze map ontvangt versleutelde bestanden. Zolang deze bestanden op dit apparaat zijn opgeslagen, kunnen ze niet vanaf dit apparaat worden geopend."
36655+
}
36656+
},
36657+
"uk" : {
36658+
"stringUnit" : {
36659+
"state" : "translated",
36660+
"value" : "Ця папка отримує зашифровані файли. Поки ці файли зберігаються на цьому пристрої, вони не можуть бути доступні з цього пристрою."
36661+
}
36662+
},
36663+
"zh-Hans" : {
36664+
"stringUnit" : {
36665+
"state" : "translated",
36666+
"value" : "此文件夹正在接收加密文件。这些文件存储在此设备上时,无法从此设备访问。"
36667+
}
36668+
}
36669+
}
36670+
},
3648736671
"This folder was deleted." : {
3648836672
"localizations" : {
3648936673
"de" : {

Sushitrain/AddFolderView.swift

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ struct AddFolderView: View {
3434
@State private var showPathSelector: Bool = false
3535
@State private var isSelective = true
3636
@State private var isPhotoFolder = false
37+
@State private var isReceiveEncryptedFolder = false
3738
@State private var photoFolderConfig = PhotoFSConfiguration()
3839
@State private var showAlert: ShowAlert? = nil
3940

41+
// Whether any device offers this folder as receive encrypted
42+
@State private var isOfferedReceiveEncrypted = false
43+
4044
var folderExists: Bool {
4145
appState.client.folder(withID: self.folderID) != nil
4246
}
@@ -75,6 +79,7 @@ struct AddFolderView: View {
7579
if !folderIDReadOnly {
7680
Button("Photo folder", systemImage: self.isPhotoFolder ? "checkmark.circle.fill" : "circle") {
7781
self.isPhotoFolder = true
82+
self.isReceiveEncryptedFolder = false
7883
}
7984
#if os(macOS)
8085
.buttonStyle(.link)
@@ -169,11 +174,23 @@ struct AddFolderView: View {
169174

170175
self.folderTypeSection()
171176

177+
if !isPhotoFolder && isOfferedReceiveEncrypted {
178+
Section {
179+
Toggle("Receive encrypted", isOn: $isReceiveEncryptedFolder)
180+
} footer: {
181+
if isReceiveEncryptedFolder {
182+
Text(
183+
"This device will receive encrypted files from other devices. The files are stored on this device, but cannot be accessed from this device."
184+
)
185+
}
186+
}
187+
}
188+
172189
if isPhotoFolder {
173190
PhotoFolderConfigurationView(config: $photoFolderConfig)
174191
}
175192

176-
if !isPhotoFolder {
193+
if !isPhotoFolder && !isReceiveEncryptedFolder {
177194
self.folderSyncTypeSection()
178195
}
179196

@@ -267,6 +284,15 @@ struct AddFolderView: View {
267284
if self.shareWithPendingPeersByDefault && sharedWith.isEmpty {
268285
sharedWith = Set(pendingPeers.filter { !(appState.client.peer(withID: $0)?.isUntrusted() ?? false) })
269286
}
287+
288+
do {
289+
var isOffered: ObjCBool = false
290+
try appState.client.isPendingFolderOfferedReceiveEncrypted(self.folderID, isOffered: &isOffered)
291+
self.isOfferedReceiveEncrypted = isOffered.boolValue
292+
}
293+
catch {
294+
self.isOfferedReceiveEncrypted = false
295+
}
270296
}
271297

272298
private func add() {
@@ -289,12 +315,19 @@ struct AddFolderView: View {
289315
try BookmarkManager.shared.saveBookmark(folderID: self.folderID, url: fp)
290316

291317
try appState.client.addFolder(
292-
self.folderID, folderPath: fp.path(percentEncoded: false),
293-
createAsOnDemand: self.isSelective)
318+
self.folderID,
319+
folderPath: fp.path(percentEncoded: false),
320+
createAsOnDemand: self.isSelective && !isReceiveEncryptedFolder,
321+
createAsReceiveEncrypted: isReceiveEncryptedFolder
322+
)
294323
}
295324
else {
296325
try appState.client.addFolder(
297-
self.folderID, folderPath: "", createAsOnDemand: self.isSelective)
326+
self.folderID,
327+
folderPath: "",
328+
createAsOnDemand: self.isSelective && !isReceiveEncryptedFolder,
329+
createAsReceiveEncrypted: isReceiveEncryptedFolder
330+
)
298331
}
299332
}
300333

Sushitrain/BrowserView.swift

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -443,14 +443,14 @@ struct BrowserView: View {
443443
} label: {
444444
Label("Add...", systemImage: "plus")
445445
}.disabled(
446-
!folderExists || !self.folder.isRegularFolder || self.folder.folderType() == SushitrainFolderTypeReceiveOnly)
446+
!folderExists || !self.folder.isRegularFolder || self.folder.isReceiveOnlyFolder)
447447
}
448448

449449
@ViewBuilder private func addMenuContents() -> some View {
450450
Button("Add files...", systemImage: "plus") {
451451
showAddFilePicker = true
452452
}.disabled(
453-
!folderExists || !self.folder.isRegularFolder || self.folder.folderType() == SushitrainFolderTypeReceiveOnly)
453+
!folderExists || !self.folder.isRegularFolder || self.folder.isReceiveOnlyFolder)
454454

455455
#if os(iOS)
456456
Button("Paste files...", systemImage: "document.on.clipboard") {
@@ -510,17 +510,20 @@ struct BrowserView: View {
510510
}
511511

512512
@ViewBuilder private func folderMenu() -> some View {
513+
let isReceiveEncrypted = folder.isReceiveEncryptedFolder
513514
Menu {
514515
if folderExists {
515516
#if os(iOS)
516-
BrowserViewStylePickerView(
517-
webViewAvailable: self.webViewAvailable,
518-
viewStyle: self.currentViewStyle()
519-
).pickerStyle(.inline)
517+
if !isReceiveEncrypted {
518+
BrowserViewStylePickerView(
519+
webViewAvailable: self.webViewAvailable,
520+
viewStyle: self.currentViewStyle()
521+
).pickerStyle(.inline)
520522

521-
self.filterMenu()
523+
self.filterMenu()
522524

523-
self.addMenu()
525+
self.addMenu()
526+
}
524527

525528
Button(openInFilesAppLabel, systemImage: "arrow.up.forward.app") {
526529
self.showInFinder()
@@ -530,14 +533,16 @@ struct BrowserView: View {
530533
#endif
531534

532535
#if os(iOS)
533-
Toggle(
534-
"Search here...",
535-
systemImage: "magnifyingglass",
536-
isOn: $showSearch
537-
).disabled(!folderExists)
536+
if !isReceiveEncrypted {
537+
Toggle(
538+
"Search here...",
539+
systemImage: "magnifyingglass",
540+
isOn: $showSearch
541+
).disabled(!folderExists)
542+
}
538543
#endif
539544

540-
if folderExists && !self.prefix.isEmpty {
545+
if folderExists && !self.prefix.isEmpty && !isReceiveEncrypted {
541546
if let entry = try? self.folder.getFileInformation(self.prefix.withoutEndingSlash) {
542547
NavigationLink(destination: FileView(file: entry, showPath: false, siblings: nil)) {
543548
Label("Subdirectory properties...", systemImage: "folder.badge.gearshape")
@@ -546,8 +551,10 @@ struct BrowserView: View {
546551
}
547552

548553
#if os(iOS)
549-
Toggle(isOn: Binding(get: { self.isBookmarked }, set: { self.setBookmarked($0) })) {
550-
Label("Bookmark", systemImage: self.isBookmarked ? "bookmark.fill" : "bookmark")
554+
if !isReceiveEncrypted {
555+
Toggle(isOn: Binding(get: { self.isBookmarked }, set: { self.setBookmarked($0) })) {
556+
Label("Bookmark", systemImage: self.isBookmarked ? "bookmark.fill" : "bookmark")
557+
}
551558
}
552559
#endif
553560

@@ -1074,7 +1081,16 @@ private struct BrowserItemsView: View {
10741081
}
10751082
}
10761083
else {
1077-
if filterAvailability != .all {
1084+
if folder.isReceiveEncryptedFolder {
1085+
ContentUnavailableView(
1086+
"The files in this folder cannot be shown",
1087+
systemImage: "lock.circle.dotted",
1088+
description: Text(
1089+
"This folder is receiving encrypted files. While these files are stored on this device, they cannot be accessed from this device."
1090+
)
1091+
)
1092+
}
1093+
else if filterAvailability != .all {
10781094
ContentUnavailableView(
10791095
"There are no files in this folder to show",
10801096
systemImage: "line.3.horizontal.decrease",

0 commit comments

Comments
 (0)