mirror of
https://github.com/nextcloud/android.git
synced 2024-11-24 22:25:44 +03:00
properly handle stage 2: key exists, but e2e is not setup on this device
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
1b945b6131
commit
e3a7453846
9 changed files with 1223 additions and 48 deletions
|
@ -1,18 +1,18 @@
|
||||||
{
|
{
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 65,
|
"version": 65,
|
||||||
"identityHash": "1aa68e80a3cb0006ef54981abad692a9",
|
"identityHash": "97be4a2bf1d8d2a4db027a996a823010",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
|
||||||
"tableName": "arbitrary_data",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)",
|
|
||||||
"fields": [
|
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"tableName": "arbitrary_data",
|
||||||
"columnName": "_id",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)",
|
||||||
"affinity": "INTEGER",
|
"fields": [
|
||||||
"notNull": false
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "_id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "cloudId",
|
"fieldPath": "cloudId",
|
||||||
|
@ -42,19 +42,19 @@
|
||||||
"indices": [],
|
"indices": [],
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"tableName": "capabilities",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT)",
|
|
||||||
"fields": [
|
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"tableName": "capabilities",
|
||||||
"columnName": "_id",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT)",
|
||||||
"affinity": "INTEGER",
|
"fields": [
|
||||||
"notNull": false
|
{
|
||||||
},
|
"fieldPath": "id",
|
||||||
{
|
"columnName": "_id",
|
||||||
"fieldPath": "accountName",
|
"affinity": "INTEGER",
|
||||||
"columnName": "account",
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "accountName",
|
||||||
|
"columnName": "account",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
@ -233,26 +233,32 @@
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "serverBackgroundUrl",
|
"fieldPath": "serverBackgroundUrl",
|
||||||
"columnName": "background_url",
|
"columnName": "background_url",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "endToEndEncryption",
|
"fieldPath": "endToEndEncryption",
|
||||||
"columnName": "end_to_end_encryption",
|
"columnName": "end_to_end_encryption",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "activity",
|
"fieldPath": "endToEndEncryptionKeysExist",
|
||||||
"columnName": "activity",
|
"columnName": "end_to_end_encryption_keys_exist",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "serverBackgroundDefault",
|
"fieldPath": "activity",
|
||||||
"columnName": "background_default",
|
"columnName": "activity",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serverBackgroundDefault",
|
||||||
|
"columnName": "background_default",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
@ -1112,7 +1118,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1aa68e80a3cb0006ef54981abad692a9')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '97be4a2bf1d8d2a4db027a996a823010')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
1124
app/schemas/com.nextcloud.client.database.NextcloudDatabase/66.json
Normal file
1124
app/schemas/com.nextcloud.client.database.NextcloudDatabase/66.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -96,6 +96,8 @@ data class CapabilityEntity(
|
||||||
val serverBackgroundUrl: String?,
|
val serverBackgroundUrl: String?,
|
||||||
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION)
|
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION)
|
||||||
val endToEndEncryption: Int?,
|
val endToEndEncryption: Int?,
|
||||||
|
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST)
|
||||||
|
val endToEndEncryptionKeysExist: Int?,
|
||||||
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_ACTIVITY)
|
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_ACTIVITY)
|
||||||
val activity: Int?,
|
val activity: Int?,
|
||||||
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT)
|
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT)
|
||||||
|
|
|
@ -1971,6 +1971,8 @@ public class FileDataStorageManager {
|
||||||
capability.getServerLogo());
|
capability.getServerLogo());
|
||||||
contentValues.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION,
|
contentValues.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION,
|
||||||
capability.getEndToEndEncryption().getValue());
|
capability.getEndToEndEncryption().getValue());
|
||||||
|
contentValues.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST,
|
||||||
|
capability.getEndToEndEncryptionKeysExist().getValue());
|
||||||
contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT,
|
contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT,
|
||||||
capability.getServerBackgroundDefault().getValue());
|
capability.getServerBackgroundDefault().getValue());
|
||||||
contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_PLAIN,
|
contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_PLAIN,
|
||||||
|
@ -2117,6 +2119,10 @@ public class FileDataStorageManager {
|
||||||
capability.setServerSlogan(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN));
|
capability.setServerSlogan(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN));
|
||||||
capability.setServerLogo(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_LOGO));
|
capability.setServerLogo(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_LOGO));
|
||||||
capability.setEndToEndEncryption(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION));
|
capability.setEndToEndEncryption(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION));
|
||||||
|
capability.setEndToEndEncryptionKeysExist(
|
||||||
|
getBoolean(cursor,
|
||||||
|
ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST)
|
||||||
|
);
|
||||||
capability.setServerBackgroundDefault(
|
capability.setServerBackgroundDefault(
|
||||||
getBoolean(cursor, ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT));
|
getBoolean(cursor, ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT));
|
||||||
capability.setServerBackgroundPlain(getBoolean(cursor,
|
capability.setServerBackgroundPlain(getBoolean(cursor,
|
||||||
|
|
|
@ -35,7 +35,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class ProviderMeta {
|
public class ProviderMeta {
|
||||||
public static final String DB_NAME = "filelist";
|
public static final String DB_NAME = "filelist";
|
||||||
public static final int DB_VERSION = 65;
|
public static final int DB_VERSION = 66;
|
||||||
|
|
||||||
private ProviderMeta() {
|
private ProviderMeta() {
|
||||||
// No instance
|
// No instance
|
||||||
|
@ -237,6 +237,7 @@ public class ProviderMeta {
|
||||||
public static final String CAPABILITIES_SERVER_BACKGROUND_DEFAULT = "background_default";
|
public static final String CAPABILITIES_SERVER_BACKGROUND_DEFAULT = "background_default";
|
||||||
public static final String CAPABILITIES_SERVER_BACKGROUND_PLAIN = "background_plain";
|
public static final String CAPABILITIES_SERVER_BACKGROUND_PLAIN = "background_plain";
|
||||||
public static final String CAPABILITIES_END_TO_END_ENCRYPTION = "end_to_end_encryption";
|
public static final String CAPABILITIES_END_TO_END_ENCRYPTION = "end_to_end_encryption";
|
||||||
|
public static final String CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST = "end_to_end_encryption_keys_exist";
|
||||||
public static final String CAPABILITIES_ACTIVITY = "activity";
|
public static final String CAPABILITIES_ACTIVITY = "activity";
|
||||||
public static final String CAPABILITIES_RICHDOCUMENT = "richdocument";
|
public static final String CAPABILITIES_RICHDOCUMENT = "richdocument";
|
||||||
public static final String CAPABILITIES_RICHDOCUMENT_MIMETYPE_LIST = "richdocument_mimetype_list";
|
public static final String CAPABILITIES_RICHDOCUMENT_MIMETYPE_LIST = "richdocument_mimetype_list";
|
||||||
|
|
|
@ -78,6 +78,7 @@ import com.owncloud.android.utils.DeviceCredentialUtils;
|
||||||
import com.owncloud.android.utils.DisplayUtils;
|
import com.owncloud.android.utils.DisplayUtils;
|
||||||
import com.owncloud.android.utils.EncryptionUtils;
|
import com.owncloud.android.utils.EncryptionUtils;
|
||||||
import com.owncloud.android.utils.MimeTypeUtil;
|
import com.owncloud.android.utils.MimeTypeUtil;
|
||||||
|
import com.owncloud.android.utils.theme.CapabilityUtils;
|
||||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -121,6 +122,7 @@ public class SettingsActivity extends PreferenceActivity
|
||||||
private static final int ACTION_CONFIRM_DEVICE_CREDENTIALS = 7;
|
private static final int ACTION_CONFIRM_DEVICE_CREDENTIALS = 7;
|
||||||
private static final int ACTION_REQUEST_CODE_DAVDROID_SETUP = 10;
|
private static final int ACTION_REQUEST_CODE_DAVDROID_SETUP = 10;
|
||||||
private static final int ACTION_SHOW_MNEMONIC = 11;
|
private static final int ACTION_SHOW_MNEMONIC = 11;
|
||||||
|
private static final int ACTION_E2E = 12;
|
||||||
private static final int TRUE_VALUE = 1;
|
private static final int TRUE_VALUE = 1;
|
||||||
|
|
||||||
private static final String DAV_PATH = "/remote.php/dav";
|
private static final String DAV_PATH = "/remote.php/dav";
|
||||||
|
@ -328,6 +330,8 @@ public class SettingsActivity extends PreferenceActivity
|
||||||
|
|
||||||
setupE2EPreference(preferenceCategoryMore);
|
setupE2EPreference(preferenceCategoryMore);
|
||||||
|
|
||||||
|
setupE2EKeysExist(preferenceCategoryMore);
|
||||||
|
|
||||||
setupE2EMnemonicPreference(preferenceCategoryMore);
|
setupE2EMnemonicPreference(preferenceCategoryMore);
|
||||||
|
|
||||||
removeE2E(preferenceCategoryMore);
|
removeE2E(preferenceCategoryMore);
|
||||||
|
@ -422,14 +426,34 @@ public class SettingsActivity extends PreferenceActivity
|
||||||
Preference preference = findPreference("setup_e2e");
|
Preference preference = findPreference("setup_e2e");
|
||||||
|
|
||||||
if (preference != null) {
|
if (preference != null) {
|
||||||
if (FileOperationsHelper.isEndToEndEncryptionSetup(this, user)) {
|
if (FileOperationsHelper.isEndToEndEncryptionSetup(this, user) ||
|
||||||
|
!CapabilityUtils.getCapability(this).getEndToEndEncryptionKeysExist().isFalse()) {
|
||||||
preferenceCategoryMore.removePreference(preference);
|
preferenceCategoryMore.removePreference(preference);
|
||||||
} else {
|
} else {
|
||||||
preference.setOnPreferenceClickListener(p -> {
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
Intent i = new Intent(MainApp.getAppContext(), SetupEncryptionActivity.class);
|
Intent i = new Intent(MainApp.getAppContext(), SetupEncryptionActivity.class);
|
||||||
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||||
i.putExtra("EXTRA_USER", user);
|
i.putExtra("EXTRA_USER", user);
|
||||||
startActivityForResult(i, ACTION_SHOW_MNEMONIC);
|
startActivityForResult(i, ACTION_E2E);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupE2EKeysExist(PreferenceCategory preferenceCategoryMore) {
|
||||||
|
Preference preference = findPreference("setup_e2e_keys_exist");
|
||||||
|
|
||||||
|
if (preference != null) {
|
||||||
|
if (!CapabilityUtils.getCapability(this).getEndToEndEncryptionKeysExist().isTrue()) {
|
||||||
|
preferenceCategoryMore.removePreference(preference);
|
||||||
|
} else {
|
||||||
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
|
Intent i = new Intent(MainApp.getAppContext(), SetupEncryptionActivity.class);
|
||||||
|
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||||
|
i.putExtra("EXTRA_USER", user);
|
||||||
|
startActivityForResult(i, ACTION_E2E);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -917,6 +941,13 @@ public class SettingsActivity extends PreferenceActivity
|
||||||
}
|
}
|
||||||
} else if (requestCode == ACTION_SHOW_MNEMONIC && resultCode == RESULT_OK) {
|
} else if (requestCode == ACTION_SHOW_MNEMONIC && resultCode == RESULT_OK) {
|
||||||
handleMnemonicRequest(data);
|
handleMnemonicRequest(data);
|
||||||
|
} else if (requestCode == ACTION_E2E) {
|
||||||
|
PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more");
|
||||||
|
|
||||||
|
setupE2EPreference(preferenceCategoryMore);
|
||||||
|
setupE2EKeysExist(preferenceCategoryMore);
|
||||||
|
setupE2EMnemonicPreference(preferenceCategoryMore);
|
||||||
|
removeE2E(preferenceCategoryMore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1066,4 +1066,5 @@
|
||||||
<string name="remove_e2e_message">You can remove end to end encryption locally on this client. The encrypted files will remain on server, but will not be synced to this computer any longer.</string>
|
<string name="remove_e2e_message">You can remove end to end encryption locally on this client. The encrypted files will remain on server, but will not be synced to this computer any longer.</string>
|
||||||
<string name="setup_e2e">During setup of end to end encryption, you will receive a random 12 word mnemonic, which you will need to open your files on other devices. This will only be stored on this device, and can be shown again in this screen. Please note it down in a secure place!</string>
|
<string name="setup_e2e">During setup of end to end encryption, you will receive a random 12 word mnemonic, which you will need to open your files on other devices. This will only be stored on this device, and can be shown again in this screen. Please note it down in a secure place!</string>
|
||||||
<string name="error_showing_encryption_dialog">Error showing setup encryption dialog!</string>
|
<string name="error_showing_encryption_dialog">Error showing setup encryption dialog!</string>
|
||||||
|
<string name="prefs_keys_exist">Add end to end encryption to this client</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -78,6 +78,10 @@
|
||||||
android:title="@string/prefs_setup_e2e"
|
android:title="@string/prefs_setup_e2e"
|
||||||
android:key="setup_e2e"
|
android:key="setup_e2e"
|
||||||
android:summary="@string/setup_e2e" />
|
android:summary="@string/setup_e2e" />
|
||||||
|
<Preference
|
||||||
|
android:title="@string/prefs_keys_exist"
|
||||||
|
android:key="setup_e2e_keys_exist"
|
||||||
|
android:summary="End to end encryption was already set up on another client. Please enter your mnemonic to allow this client to sync and decrypt the files." />
|
||||||
<Preference
|
<Preference
|
||||||
android:title="@string/prefs_e2e_active"
|
android:title="@string/prefs_e2e_active"
|
||||||
android:key="mnemonic"
|
android:key="mnemonic"
|
||||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
||||||
daggerVersion = "2.44.2"
|
daggerVersion = "2.44.2"
|
||||||
markwonVersion = "4.6.2"
|
markwonVersion = "4.6.2"
|
||||||
prismVersion = "2.0.0"
|
prismVersion = "2.0.0"
|
||||||
androidLibraryVersion = "master-SNAPSHOT"
|
androidLibraryVersion = "e2eKey-SNAPSHOT"
|
||||||
mockitoVersion = "4.9.0"
|
mockitoVersion = "4.9.0"
|
||||||
mockitoKotlinVersion = "4.0.0"
|
mockitoKotlinVersion = "4.0.0"
|
||||||
mockkVersion = "1.13.2"
|
mockkVersion = "1.13.2"
|
||||||
|
|
Loading…
Reference in a new issue