forked from hardcoresushi/DroidFS
Best error messages when opening volumes
This commit is contained in:
parent
f4f3239bb1
commit
4c412be7dc
@ -1 +1 @@
|
||||
Subproject commit f40c2bbdcde77d8128da181edb72bf0e7a2168b5
|
||||
Subproject commit 3c56f86d86afacaf4a07ae77aa3d146764d587ec
|
@ -1 +1 @@
|
||||
Subproject commit 79f9a10e35847e46f8563941345355f15f2dba7c
|
||||
Subproject commit 6308adf8e57379e1136f4f55ff0d7737c0d0a33b
|
@ -2,8 +2,12 @@ package sushi.hardcore.droidfs
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import sushi.hardcore.droidfs.filesystems.CryfsVolume
|
||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||
import sushi.hardcore.droidfs.filesystems.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
class VolumeData(val name: String, val isHidden: Boolean = false, val type: Byte, var encryptedHash: ByteArray? = null, var iv: ByteArray? = null): Parcelable {
|
||||
|
||||
@ -26,6 +30,28 @@ class VolumeData(val name: String, val isHidden: Boolean = false, val type: Byte
|
||||
name
|
||||
}
|
||||
|
||||
fun canRead(filesDir: String): Boolean {
|
||||
val volumePath = getFullPath(filesDir)
|
||||
if (!File(volumePath).canRead()) {
|
||||
return false
|
||||
}
|
||||
val configFile = when (type) {
|
||||
EncryptedVolume.GOCRYPTFS_VOLUME_TYPE -> PathUtils.pathJoin(volumePath, GocryptfsVolume.CONFIG_FILE_NAME)
|
||||
EncryptedVolume.CRYFS_VOLUME_TYPE -> PathUtils.pathJoin(volumePath, CryfsVolume.CONFIG_FILE_NAME)
|
||||
else -> return false
|
||||
}
|
||||
var success = true
|
||||
try {
|
||||
with (FileInputStream(configFile)) {
|
||||
read()
|
||||
close()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
success = false
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
fun canWrite(filesDir: String): Boolean {
|
||||
return File(getFullPath(filesDir)).canWrite()
|
||||
}
|
||||
|
@ -39,6 +39,14 @@ class VolumeOpener(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getErrorMsg(result: EncryptedVolume.InitResult): String {
|
||||
return if (result.errorStringId == 0) {
|
||||
activity.getString(R.string.unknown_error_code, result.errorCode)
|
||||
} else {
|
||||
activity.getString(result.errorStringId)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi") // fingerprintProtector is non-null only when SDK_INT >= 23
|
||||
fun openVolume(volume: VolumeData, isVolumeSaved: Boolean, callbacks: VolumeOpenerCallbacks) {
|
||||
val volumeId = volumeManager.getVolumeId(volume)
|
||||
@ -60,17 +68,18 @@ class VolumeOpener(
|
||||
callbacks.onHashStorageReset()
|
||||
}
|
||||
override fun onPasswordHashDecrypted(hash: ByteArray) {
|
||||
object : LoadingTask<EncryptedVolume?>(activity, theme, R.string.loading_msg_open) {
|
||||
override suspend fun doTask(): EncryptedVolume? {
|
||||
val encryptedVolume = EncryptedVolume.init(volume, activity.filesDir.path, null, hash, null)
|
||||
object : LoadingTask<EncryptedVolume.InitResult>(activity, theme, R.string.loading_msg_open) {
|
||||
override suspend fun doTask(): EncryptedVolume.InitResult {
|
||||
val result = EncryptedVolume.init(volume, activity.filesDir.path, null, hash, null)
|
||||
Arrays.fill(hash, 0)
|
||||
return encryptedVolume
|
||||
return result
|
||||
}
|
||||
}.startTask(activity.lifecycleScope) { encryptedVolume ->
|
||||
}.startTask(activity.lifecycleScope) { result ->
|
||||
val encryptedVolume = result.volume
|
||||
if (encryptedVolume == null) {
|
||||
CustomAlertDialogBuilder(activity, theme)
|
||||
.setTitle(R.string.open_volume_failed)
|
||||
.setMessage(R.string.open_failed_hash_msg)
|
||||
.setMessage(getErrorMsg(result))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else {
|
||||
@ -168,17 +177,18 @@ class VolumeOpener(
|
||||
} else {
|
||||
null
|
||||
}
|
||||
object : LoadingTask<EncryptedVolume?>(activity, theme, R.string.loading_msg_open) {
|
||||
override suspend fun doTask(): EncryptedVolume? {
|
||||
val encryptedVolume = EncryptedVolume.init(volume, activity.filesDir.path, password, null, returnedHash)
|
||||
object : LoadingTask<EncryptedVolume.InitResult>(activity, theme, R.string.loading_msg_open) {
|
||||
override suspend fun doTask(): EncryptedVolume.InitResult {
|
||||
val result = EncryptedVolume.init(volume, activity.filesDir.path, password, null, returnedHash)
|
||||
Arrays.fill(password, 0)
|
||||
return encryptedVolume
|
||||
return result
|
||||
}
|
||||
}.startTask(activity.lifecycleScope) { encryptedVolume ->
|
||||
}.startTask(activity.lifecycleScope) { result ->
|
||||
val encryptedVolume = result.volume
|
||||
if (encryptedVolume == null) {
|
||||
CustomAlertDialogBuilder(activity, theme)
|
||||
.setTitle(R.string.open_volume_failed)
|
||||
.setMessage(R.string.open_volume_failed_msg)
|
||||
.setMessage(getErrorMsg(result))
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
askForPassword(volume, isVolumeSaved, callbacks, savePasswordHash)
|
||||
}
|
||||
|
@ -92,8 +92,10 @@ class VolumeAdapter(
|
||||
itemView.findViewById<TextView>(R.id.text_info).text = context.getString(
|
||||
if (volume.canWrite(context.filesDir.path)) {
|
||||
R.string.volume_type
|
||||
} else {
|
||||
} else if (volume.canRead(context.filesDir.path)) {
|
||||
R.string.volume_type_read_only
|
||||
} else {
|
||||
R.string.volume_type_inaccessible
|
||||
},
|
||||
context.getString(if (volume.type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE) {
|
||||
R.string.gocryptfs
|
||||
|
@ -190,14 +190,14 @@ class CreateVolumeFragment: Fragment() {
|
||||
encryptedVolume,
|
||||
), EncryptedVolume.GOCRYPTFS_VOLUME_TYPE)
|
||||
} else {
|
||||
generateResult(CryfsVolume.create(
|
||||
encryptedVolume.value = CryfsVolume.create(
|
||||
volumePath,
|
||||
CryfsVolume.getLocalStateDir(activity.filesDir.path),
|
||||
password,
|
||||
returnedHash,
|
||||
resources.getStringArray(R.array.cryfs_encryption_ciphers)[binding.spinnerCipher.selectedItemPosition],
|
||||
encryptedVolume,
|
||||
), EncryptedVolume.CRYFS_VOLUME_TYPE)
|
||||
)
|
||||
generateResult(encryptedVolume.value != null, EncryptedVolume.CRYFS_VOLUME_TYPE)
|
||||
}
|
||||
Arrays.fill(password, 0)
|
||||
return result
|
||||
|
@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.filesystems
|
||||
|
||||
import android.os.Parcel
|
||||
import sushi.hardcore.droidfs.Constants
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.util.ObjRef
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
@ -21,7 +22,8 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||
givenHash: ByteArray?,
|
||||
returnedHash: ObjRef<ByteArray?>?,
|
||||
createBaseDir: Boolean,
|
||||
cipher: String?
|
||||
cipher: String?,
|
||||
errorCode: ObjRef<Int?>,
|
||||
): Long
|
||||
private external fun nativeChangeEncryptionKey(
|
||||
baseDir: String,
|
||||
@ -58,22 +60,30 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||
returnedHash: ObjRef<ByteArray?>?,
|
||||
createBaseDir: Boolean,
|
||||
cipher: String?
|
||||
): CryfsVolume? {
|
||||
val fusePtr = nativeInit(baseDir, localStateDir, password, givenHash, returnedHash, createBaseDir, cipher)
|
||||
return if (fusePtr == 0L) {
|
||||
null
|
||||
): InitResult {
|
||||
val errorCode = ObjRef<Int?>(null)
|
||||
val fusePtr = nativeInit(baseDir, localStateDir, password, givenHash, returnedHash, createBaseDir, cipher, errorCode)
|
||||
val result = InitResult.Builder()
|
||||
if (fusePtr == 0L) {
|
||||
result.errorCode = errorCode.value ?: 0
|
||||
result.errorStringId = when (errorCode.value) {
|
||||
// Values from src/cryfs/impl/ErrorCodes.h
|
||||
11 -> R.string.wrong_password
|
||||
19 -> R.string.config_load_error
|
||||
20 -> R.string.filesystem_id_changed
|
||||
else -> 0
|
||||
}
|
||||
} else {
|
||||
CryfsVolume(fusePtr)
|
||||
result.volume = CryfsVolume(fusePtr)
|
||||
}
|
||||
return result.build()
|
||||
}
|
||||
|
||||
fun create(baseDir: String, localStateDir: String, password: ByteArray, returnedHash: ObjRef<ByteArray?>?, cipher: String?, volume: ObjRef<EncryptedVolume?>): Boolean {
|
||||
return init(baseDir, localStateDir, password, null, returnedHash, true, cipher)?.also {
|
||||
volume.value = it
|
||||
} != null
|
||||
fun create(baseDir: String, localStateDir: String, password: ByteArray, returnedHash: ObjRef<ByteArray?>?, cipher: String?): EncryptedVolume? {
|
||||
return init(baseDir, localStateDir, password, null, returnedHash, true, cipher).volume
|
||||
}
|
||||
|
||||
fun init(baseDir: String, localStateDir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ObjRef<ByteArray?>?): CryfsVolume? {
|
||||
fun init(baseDir: String, localStateDir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ObjRef<ByteArray?>?): InitResult {
|
||||
return init(baseDir, localStateDir, password, givenHash, returnedHash, false, null)
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,17 @@ import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
abstract class EncryptedVolume: Parcelable {
|
||||
|
||||
class InitResult(val errorCode: Int, val errorStringId: Int, val volume: EncryptedVolume?) {
|
||||
class Builder {
|
||||
var errorCode = 0
|
||||
var errorStringId = 0
|
||||
var volume: EncryptedVolume? = null
|
||||
|
||||
fun build() = InitResult(errorCode, errorStringId, volume)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val GOCRYPTFS_VOLUME_TYPE: Byte = 0
|
||||
const val CRYFS_VOLUME_TYPE: Byte = 1
|
||||
@ -31,6 +42,11 @@ abstract class EncryptedVolume: Parcelable {
|
||||
override fun newArray(size: Int) = arrayOfNulls<EncryptedVolume>(size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of a volume.
|
||||
*
|
||||
* @return The volume type or -1 if the path is not recognized as a volume
|
||||
*/
|
||||
fun getVolumeType(path: String): Byte {
|
||||
return if (File(path, GocryptfsVolume.CONFIG_FILE_NAME).isFile) {
|
||||
GOCRYPTFS_VOLUME_TYPE
|
||||
@ -47,7 +63,7 @@ abstract class EncryptedVolume: Parcelable {
|
||||
password: ByteArray?,
|
||||
givenHash: ByteArray?,
|
||||
returnedHash: ObjRef<ByteArray?>?
|
||||
): EncryptedVolume? {
|
||||
): InitResult {
|
||||
return when (volume.type) {
|
||||
GOCRYPTFS_VOLUME_TYPE -> {
|
||||
GocryptfsVolume.init(
|
||||
|
@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.filesystems
|
||||
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.util.ObjRef
|
||||
import kotlin.math.min
|
||||
@ -75,13 +76,20 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
|
||||
}
|
||||
}
|
||||
|
||||
fun init(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): GocryptfsVolume? {
|
||||
fun init(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): InitResult {
|
||||
val sessionId = nativeInit(root_cipher_dir, password, givenHash, returnedHash)
|
||||
return if (sessionId == -1) {
|
||||
null
|
||||
val result = InitResult.Builder()
|
||||
if (sessionId < 0) {
|
||||
result.errorCode = sessionId
|
||||
result.errorStringId = when (sessionId) {
|
||||
-1 -> R.string.config_load_error
|
||||
-2 -> R.string.wrong_password
|
||||
else -> 0
|
||||
}
|
||||
} else {
|
||||
GocryptfsVolume(sessionId)
|
||||
result.volume = GocryptfsVolume(sessionId)
|
||||
}
|
||||
return result.build()
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -7,9 +7,9 @@ Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeInit(JN
|
||||
jstring base_dir, jstring jlocalStateDir,
|
||||
jbyteArray password, jbyteArray givenHash,
|
||||
jobject returnedHash,
|
||||
jboolean createBaseDir,
|
||||
jstring cipher) {
|
||||
return cryfs_init(env, base_dir, jlocalStateDir, password, givenHash, returnedHash, createBaseDir, cipher);
|
||||
jboolean createBaseDir, jstring cipher,
|
||||
jobject jerrorCode) {
|
||||
return cryfs_init(env, base_dir, jlocalStateDir, password, givenHash, returnedHash, createBaseDir, cipher, jerrorCode);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
|
@ -27,7 +27,6 @@
|
||||
<string name="dir_not_empty">إن المجلد المحدد ليس فارغاً</string>
|
||||
<string name="create_volume_failed">إن عملية إنشاء المجلد المشفر قد فشلت.</string>
|
||||
<string name="open_volume_failed">عملية الفتح قد فشلت</string>
|
||||
<string name="open_volume_failed_msg">لقد تعذر فتح المجلد المشفر. من فضلك تحقق من كلمة المرور.</string>
|
||||
<string name="share_chooser">مشاركة ملف</string>
|
||||
<string name="storage_perm_denied">إن صلاحية التخزين مرفوضة</string>
|
||||
<string name="storage_perm_denied_msg">إن DroidFS لا يمكنه العمل بدون صلاحبات التخزين.</string>
|
||||
@ -58,7 +57,6 @@
|
||||
<string name="listdir_null_error_msg">تعذر الوصول إلى هذا المسار</string>
|
||||
<string name="fingerprint_save_checkbox_text">حفظ كلمة المرور ببصمة الإصبع</string>
|
||||
<string name="fingerprint_instruction">يرجى لمس مستشعر بصمة الإصبع</string>
|
||||
<string name="open_failed_hash_msg">فشل في فتح المجلد المشفر. ربما تغيرت كلمة المرور.</string>
|
||||
<string name="illegal_block_size_exception">IllegalBlockSizeException</string>
|
||||
<string name="illegal_block_size_exception_msg">يمكن أن يحدث هذا إذا أضفت بصمة إصبع جديدة. يمكنك أن تقوم بإعادة تعيين تخزين التجزئة لحل هذه المشكلة.</string>
|
||||
<string name="reset_hash_storage">إعادة تعيين تخزين التجزئة</string>
|
||||
|
@ -28,7 +28,6 @@
|
||||
<string name="dir_not_empty">El directorio seleccionado no está vacío</string>
|
||||
<string name="create_volume_failed">La creación del volumen ha fallado.</string>
|
||||
<string name="open_volume_failed">Fallo al abrir</string>
|
||||
<string name="open_volume_failed_msg">No se ha podido abrir el volumen. Por favor, comprueba tu contraseña.</string>
|
||||
<string name="share_chooser">Compartir archivo</string>
|
||||
<string name="storage_perm_denied">Permiso de almacenamiento denegado</string>
|
||||
<string name="storage_perm_denied_msg">DroidFS no puede funcionar sin permisos de almacenamiento.</string>
|
||||
@ -59,7 +58,6 @@
|
||||
<string name="listdir_null_error_msg">No se puede acceder a este directorio</string>
|
||||
<string name="fingerprint_save_checkbox_text">Guardar el hash de la contraseña mediante la huella dactilar</string>
|
||||
<string name="fingerprint_instruction">Por favor, toca el sensor de huellas dactilares</string>
|
||||
<string name="open_failed_hash_msg">No se ha podido abrir el volumen. La contraseña puede haber cambiado.</string>
|
||||
<string name="illegal_block_size_exception">IllegalBlockSizeException</string>
|
||||
<string name="illegal_block_size_exception_msg">Esto puede ocurrir si has añadido una nueva huella digital. Restablecer el almacenamiento de hash puede resolver este problema.</string>
|
||||
<string name="reset_hash_storage">Restablecer el almacenamiento de hash</string>
|
||||
|
@ -27,7 +27,6 @@
|
||||
<string name="dir_not_empty">A pasta selecionada não está vazia</string>
|
||||
<string name="create_volume_failed">Falha ao criar o volume.</string>
|
||||
<string name="open_volume_failed">Não foi possível abrir</string>
|
||||
<string name="open_volume_failed_msg">Falha ao abrir o volume. Por favor, verifique sua senha.</string>
|
||||
<string name="share_chooser">Compartilhar arquivo</string>
|
||||
<string name="storage_perm_denied">Permissão do armazenamento negada</string>
|
||||
<string name="storage_perm_denied_msg">DroidFS não pode funcionar sem permissão ao armazenamento.</string>
|
||||
@ -58,7 +57,6 @@
|
||||
<string name="listdir_null_error_msg">Não foi possível acessar a pasta</string>
|
||||
<string name="fingerprint_save_checkbox_text">Salvar o hash da senha usando impressão digital</string>
|
||||
<string name="fingerprint_instruction">Por favor, toque no sensor da impressão digital</string>
|
||||
<string name="open_failed_hash_msg">Falha ao abrir o volume. A senha podia ter mudado.</string>
|
||||
<string name="illegal_block_size_exception">IllegalBlockSizeException</string>
|
||||
<string name="illegal_block_size_exception_msg">Isto poderia ter acontecido, se você tiver adicionado uma nova impressão digital. Tente resetar o hash do armazenamento para resolver este problema.</string>
|
||||
<string name="reset_hash_storage">Resetar o hash do armazenamento</string>
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="dir_not_empty">Выбранная папка не пустая</string>
|
||||
<string name="create_volume_failed">Невозможно создать том.</string>
|
||||
<string name="open_volume_failed">Ошибка открытия</string>
|
||||
<string name="open_volume_failed_msg">Невозможно открыть том. Проверьте пароль.</string>
|
||||
<string name="share_chooser">Поделиться файлом</string>
|
||||
<string name="storage_perm_denied">Доступ к хранилищу запрещён</string>
|
||||
<string name="storage_perm_denied_msg">DroidFS не может работать без разрешения на доступ к хранилищу.</string>
|
||||
@ -57,7 +56,6 @@
|
||||
<string name="listdir_null_error_msg">Невозможно получить доступ к этой папке.</string>
|
||||
<string name="fingerprint_save_checkbox_text">Сохранить хеш пароля отпечатком пальца</string>
|
||||
<string name="fingerprint_instruction">Прикоснитесь к сканеру отпечатков пальцев</string>
|
||||
<string name="open_failed_hash_msg">Невозможно открыть том. Возможно, изменился пароль.</string>
|
||||
<string name="illegal_block_size_exception_msg">Это могло произойти, если вы добавили новый отпечаток пальца. Сброс хранилища хешей должен решить эту проблему.</string>
|
||||
<string name="reset_hash_storage">Сброс хранилища хешей</string>
|
||||
<string name="MAC_verification_failed">Проверка подписи/MAC не выполнена. Хранилище ключей Android или сохранённый хеш был изменён. Сброс хранилища хешей должен решить эту проблему.</string>
|
||||
|
@ -28,7 +28,6 @@
|
||||
<string name="dir_not_empty">The selected directory isn\'t empty</string>
|
||||
<string name="create_volume_failed">The volume creation has failed.</string>
|
||||
<string name="open_volume_failed">Open failed</string>
|
||||
<string name="open_volume_failed_msg">Failed to open the volume. Please check your password.</string>
|
||||
<string name="share_chooser">Share File</string>
|
||||
<string name="storage_perm_denied">Storage permission denied</string>
|
||||
<string name="storage_perm_denied_msg">DroidFS can\'t work without storage permissions.</string>
|
||||
@ -59,7 +58,6 @@
|
||||
<string name="listdir_null_error_msg">Unable to access this directory</string>
|
||||
<string name="fingerprint_save_checkbox_text">Save password hash using fingerprint</string>
|
||||
<string name="fingerprint_instruction">Please touch the fingerprint sensor</string>
|
||||
<string name="open_failed_hash_msg">Failed to open the volume. The password may have changed.</string>
|
||||
<string name="illegal_block_size_exception">IllegalBlockSizeException</string>
|
||||
<string name="illegal_block_size_exception_msg">This can happen if you have added a new fingerprint. Resetting hash storage can solve this problem.</string>
|
||||
<string name="reset_hash_storage">Reset hash storage</string>
|
||||
@ -244,6 +242,7 @@
|
||||
<string name="file_op_delete_msg">Deleting files…</string>
|
||||
<string name="volume_type">(%s)</string>
|
||||
<string name="volume_type_read_only">(%s, read-only)</string>
|
||||
<string name="volume_type_inaccessible">(%s, inaccessible)</string>
|
||||
<string name="io_error">I/O Error.</string>
|
||||
<string name="use_fingerprint">Use fingerprint instead of current password</string>
|
||||
<string name="remember_volume">Remember volume</string>
|
||||
@ -258,4 +257,8 @@
|
||||
<string name="black_theme">Black theme</string>
|
||||
<string name="password_fallback">Fallback to password</string>
|
||||
<string name="password_fallback_summary">Prompt for password when fingerprint authentication is cancelled</string>
|
||||
<string name="unknown_error_code">Unknown error code: %d</string>
|
||||
<string name="config_load_error">The configuration file cannot be loaded. Make sure the volume is accessible.</string>
|
||||
<string name="wrong_password">The configuration file cannot be decrypted. Please check your password.</string>
|
||||
<string name="filesystem_id_changed">The filesystem id in the config file is different to the last time we opened this volume. This could mean an attacker replaced the filesystem with a different one.</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user