Skip to content

Commit

Permalink
Merge pull request #32 from SecUSo/development
Browse files Browse the repository at this point in the history
Update to version 1.3.3
  • Loading branch information
udenr authored Nov 12, 2024
2 parents 064bf80 + 7183987 commit dc660d2
Show file tree
Hide file tree
Showing 17 changed files with 723 additions and 204 deletions.
6 changes: 3 additions & 3 deletions BackupApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ android {
applicationId "org.secuso.privacyfriendlybackup"
minSdkVersion 21
targetSdkVersion 34
versionCode 6
versionName "1.3.2"
versionCode 7
versionName "1.3.3"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand Down Expand Up @@ -82,7 +82,7 @@ android {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
lint {
abortOnError false
lintConfig = file("lint.xml")
}
namespace 'org.secuso.privacyfriendlybackup'
}
Expand Down
11 changes: 11 additions & 0 deletions BackupApp/lint.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Disable the NotificationPermission check for glide -->
<issue id="NotificationPermission">
<ignore regexp="com.bumptech.glide.request.target.NotificationTarget" />
</issue>

<!-- Set the severity of missing translations to warning instead of error -->
<issue id="MissingTranslation" severity="warning" />
<issue id="MissingQuantity" severity="warning" />
</lint>
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,68 @@ import android.util.JsonWriter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.secuso.privacyfriendlybackup.data.BackupDataStorageRepository
import java.io.BufferedWriter
import java.io.IOException
import java.io.OutputStreamWriter
import java.text.FieldPosition
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

class DataExporter {
companion object {
suspend fun exportData(context: Context, uri: Uri, data: BackupDataStorageRepository.BackupData) : Boolean{
suspend fun exportDataZip(context: Context, uri: Uri, data: Set<BackupDataStorageRepository.BackupData>): Boolean {
return withContext(Dispatchers.IO) {
try {
ParcelFileDescriptor.AutoCloseOutputStream(
context.contentResolver.openFileDescriptor(uri, "w")
).use { out ->
JsonWriter(OutputStreamWriter(out, Charsets.UTF_8)).use { writer ->
writer.setIndent(" ")
writer.beginObject()
writeData(writer, data)
writer.endObject()
ZipOutputStream(ParcelFileDescriptor.AutoCloseOutputStream(context.contentResolver.openFileDescriptor(uri, "w"))).apply {
setLevel(5)
setComment("PFA Backup Export")
}.use { zipOut ->
data.forEach { backupData ->
val zipEntry = ZipEntry(getSingleExportFileName(backupData, backupData.encrypted))
zipOut.putNextEntry(zipEntry)

val osw = OutputStreamWriter(zipOut, Charsets.UTF_8)
val bw = BufferedWriter(osw)
val jw = JsonWriter(bw)
jw.let { writer ->
writer.setIndent(" ")
writer.beginObject()
writeData(writer, backupData)
writer.endObject()
}
jw.flush()
bw.flush()
osw.flush()

zipOut.closeEntry()
}
}
} catch (e : IOException) {
} catch (e: IOException) {
e.printStackTrace()
return@withContext false
}
return@withContext true
}
}

suspend fun exportData(context: Context, uri: Uri, data: BackupDataStorageRepository.BackupData): Boolean {
return withContext(Dispatchers.IO) {
try {
JsonWriter(
OutputStreamWriter(
ParcelFileDescriptor.AutoCloseOutputStream(context.contentResolver.openFileDescriptor(uri, "w")),
Charsets.UTF_8
)
).use { writer ->
writer.setIndent(" ")
writer.beginObject()
writeData(writer, data)
writer.endObject()
}
} catch (e: IOException) {
return@withContext false
}
return@withContext true
Expand All @@ -39,5 +82,40 @@ class DataExporter {
writer.name("encrypted").value(metaData.encrypted)
writer.name("data").value(String(metaData.data!!))
}

/**
* Filename for export containing multiple backups (.zip)
*/
fun getMultipleExportFileName(): String {
val sb = StringBuffer()
sb.append("PfaBackup_")
val sdf = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.getDefault())
sdf.format(Calendar.getInstance().time, sb, FieldPosition(SimpleDateFormat.DATE_FIELD))
sb.append(".zip")
return sb.toString()
}

/**
* Filename for single Backup export (.backup)
*/
fun getSingleExportFileName(backupMetaData: BackupDataStorageRepository.BackupData, encrypted: Boolean): String {
return if (backupMetaData.encrypted && encrypted) {
getEncryptedFilename(backupMetaData.filename)
} else {
getUnencryptedFilename(backupMetaData.filename)
}
}


private fun getUnencryptedFilename(filename: String) =
filename.replace("_encrypted.backup", ".backup")

private fun getEncryptedFilename(filename: String): String {
return if (filename.contains("_encrypted.backup", true)) {
filename
} else {
filename.replace(".backup", "_encrypted.backup", true)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,66 @@ import org.secuso.privacyfriendlybackup.data.BackupDataStorageRepository
import org.secuso.privacyfriendlybackup.data.room.model.enums.StorageType
import java.io.IOException
import java.io.InputStreamReader
import java.util.*
import java.util.Date
import java.util.LinkedList
import java.util.zip.ZipInputStream


class DataImporter {

companion object {
suspend fun importData(context: Context, uri: Uri) : Pair<Boolean, BackupDataStorageRepository.BackupData?> {
suspend fun importDataZip(context: Context, uri: Uri): List<Pair<Boolean, Long?>>? {
return withContext(IO) {
var backupData : BackupDataStorageRepository.BackupData? = null
val descriptor = context.contentResolver.openFileDescriptor(uri, "r")
val inStream = ParcelFileDescriptor.AutoCloseInputStream(descriptor)
val zipInStream = ZipInputStream(inStream)
val result: MutableList<Pair<Boolean, Long?>> = LinkedList()

try {
zipInStream.use { zipInputStream ->
generateSequence { zipInputStream.nextEntry }
.filterNot { it.isDirectory }
.forEach { _ ->
var backupData: BackupDataStorageRepository.BackupData? = null
val isr = InputStreamReader(zipInputStream, Charsets.UTF_8)
val jr = JsonReader(isr)
jr.let { reader ->
reader.beginObject()
backupData = readData(reader)
reader.endObject()
}
if (backupData != null) {

if (!backupData!!.encrypted) {
// short validation check if the json is valid
if (!isValidJSON(String(backupData!!.data!!))) {
result.add(false to null)
}
}

result.add(
BackupDataStorageRepository.getInstance(context).storeFile(
context,
backupData!!
)
)
} else {
result.add(false to null)
}
}
}
} catch (e: MalformedJsonException) {
return@withContext null
} catch (e: IOException) {
return@withContext null
}
return@withContext result
}
}

suspend fun importData(context: Context, uri: Uri): Pair<Boolean, BackupDataStorageRepository.BackupData?> {
return withContext(IO) {
var backupData: BackupDataStorageRepository.BackupData? = null

val descriptor = context.contentResolver.openFileDescriptor(uri, "r")
val inStream = ParcelFileDescriptor.AutoCloseInputStream(descriptor)
Expand All @@ -40,13 +91,13 @@ class DataImporter {
return@withContext false to null
}

val result : Pair<Boolean, Long>
val result: Pair<Boolean, Long>

if(backupData != null) {
if (backupData != null) {

if(!backupData!!.encrypted) {
if (!backupData!!.encrypted) {
// short validation check if the json is valid
if(!isValidJSON(String(backupData!!.data!!))) {
if (!isValidJSON(String(backupData!!.data!!))) {
return@withContext false to null
}
}
Expand Down Expand Up @@ -75,17 +126,17 @@ class DataImporter {
}
}

private fun readData(reader: JsonReader) : BackupDataStorageRepository.BackupData? {
var filename : String? = null
var packageName : String? = null
var timestamp : Long? = null
var encrypted : Boolean? = null
var data : String? = null
private fun readData(reader: JsonReader): BackupDataStorageRepository.BackupData? {
var filename: String? = null
var packageName: String? = null
var timestamp: Long? = null
var encrypted: Boolean? = null
var data: String? = null

while (reader.hasNext()) {
val nextName = reader.nextName()

when(nextName) {
when (nextName) {
"filename" -> filename = reader.nextString()
"packageName" -> packageName = reader.nextString()
"timestamp" -> timestamp = reader.nextLong()
Expand All @@ -95,11 +146,12 @@ class DataImporter {
}
}

if(TextUtils.isEmpty(filename)
if (TextUtils.isEmpty(filename)
|| TextUtils.isEmpty(packageName)
|| TextUtils.isEmpty(data)
|| timestamp == null
|| encrypted == null) {
|| encrypted == null
) {
return null
}

Expand Down
Loading

0 comments on commit dc660d2

Please sign in to comment.