mirror of
https://github.com/android-password-store/Android-Password-Store
synced 2025-09-01 06:45:19 +00:00
Upgrade to Kotlin 1.4 (#978)
* build: uprev to Kotlin 1.4 Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Remove explicit type argument Not required anymore with Kotlin 1.4 Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * build: enable Kotlin 1.4 language features Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * all: add trailing commas where reasonable Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> Co-authored-by: Fabian Henneke <FabianHenneke@users.noreply.github.com>
This commit is contained in:
@@ -95,8 +95,11 @@ class UserPreference : AppCompatActivity() {
|
|||||||
|
|
||||||
if (!PasswordRepository.isGitRepo()) {
|
if (!PasswordRepository.isGitRepo()) {
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
gitServerPreference, gitConfigPreference, sshKeyPreference,
|
gitServerPreference,
|
||||||
viewSshKeyPreference, clearSavedPassPreference
|
gitConfigPreference,
|
||||||
|
sshKeyPreference,
|
||||||
|
viewSshKeyPreference,
|
||||||
|
clearSavedPassPreference,
|
||||||
).forEach {
|
).forEach {
|
||||||
it.parent?.removePreference(it)
|
it.parent?.removePreference(it)
|
||||||
}
|
}
|
||||||
@@ -119,12 +122,12 @@ class UserPreference : AppCompatActivity() {
|
|||||||
autoFillAppsPreference,
|
autoFillAppsPreference,
|
||||||
autoFillDefaultPreference,
|
autoFillDefaultPreference,
|
||||||
autoFillAlwaysShowDialogPreference,
|
autoFillAlwaysShowDialogPreference,
|
||||||
autoFillShowFullNamePreference
|
autoFillShowFullNamePreference,
|
||||||
)
|
)
|
||||||
oreoAutofillDependencies = listOfNotNull(
|
oreoAutofillDependencies = listOfNotNull(
|
||||||
oreoAutofillDirectoryStructurePreference,
|
oreoAutofillDirectoryStructurePreference,
|
||||||
oreoAutofillDefaultUsername,
|
oreoAutofillDefaultUsername,
|
||||||
oreoAutofillCustomPublixSuffixes
|
oreoAutofillCustomPublixSuffixes,
|
||||||
)
|
)
|
||||||
oreoAutofillCustomPublixSuffixes?.apply {
|
oreoAutofillCustomPublixSuffixes?.apply {
|
||||||
setOnBindEditTextListener {
|
setOnBindEditTextListener {
|
||||||
|
@@ -232,7 +232,8 @@ class AutofillRule private constructor(
|
|||||||
fun genericPassword(optional: Boolean = false, block: FieldMatcher.Builder.() -> Unit) {
|
fun genericPassword(optional: Boolean = false, block: FieldMatcher.Builder.() -> Unit) {
|
||||||
require(matchers.none {
|
require(matchers.none {
|
||||||
it.type in listOf(
|
it.type in listOf(
|
||||||
FillableFieldType.CurrentPassword, FillableFieldType.NewPassword
|
FillableFieldType.CurrentPassword,
|
||||||
|
FillableFieldType.NewPassword,
|
||||||
)
|
)
|
||||||
}) { "Every rule block can only have either genericPassword or {current,new}Password blocks" }
|
}) { "Every rule block can only have either genericPassword or {current,new}Password blocks" }
|
||||||
matchers.add(
|
matchers.add(
|
||||||
|
@@ -74,7 +74,7 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH = mapOf(
|
|||||||
"org.mozilla.firefox_beta" to "p4tipRZbRJSy/q2edqKA0i2Tf+5iUa7OWZRGsuoxmwQ=",
|
"org.mozilla.firefox_beta" to "p4tipRZbRJSy/q2edqKA0i2Tf+5iUa7OWZRGsuoxmwQ=",
|
||||||
"org.mozilla.focus" to "YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w=",
|
"org.mozilla.focus" to "YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w=",
|
||||||
"org.mozilla.klar" to "YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w=",
|
"org.mozilla.klar" to "YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w=",
|
||||||
"org.torproject.torbrowser" to "IAYfBF5zfGc3XBd5TP7bQ2oDzsa6y3y5+WZCIFyizsg="
|
"org.torproject.torbrowser" to "IAYfBF5zfGc3XBd5TP7bQ2oDzsa6y3y5+WZCIFyizsg=",
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun isTrustedBrowser(context: Context, appPackage: String): Boolean {
|
private fun isTrustedBrowser(context: Context, appPackage: String): Boolean {
|
||||||
@@ -112,7 +112,7 @@ private val BROWSER_MULTI_ORIGIN_METHOD = mapOf(
|
|||||||
"org.mozilla.firefox_beta" to BrowserMultiOriginMethod.WebView,
|
"org.mozilla.firefox_beta" to BrowserMultiOriginMethod.WebView,
|
||||||
"org.mozilla.focus" to BrowserMultiOriginMethod.Field,
|
"org.mozilla.focus" to BrowserMultiOriginMethod.Field,
|
||||||
"org.mozilla.klar" to BrowserMultiOriginMethod.Field,
|
"org.mozilla.klar" to BrowserMultiOriginMethod.Field,
|
||||||
"org.torproject.torbrowser" to BrowserMultiOriginMethod.WebView
|
"org.torproject.torbrowser" to BrowserMultiOriginMethod.WebView,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getBrowserMultiOriginMethod(appPackage: String): BrowserMultiOriginMethod =
|
private fun getBrowserMultiOriginMethod(appPackage: String): BrowserMultiOriginMethod =
|
||||||
@@ -135,7 +135,7 @@ private val BROWSER_SAVE_FLAG = mapOf(
|
|||||||
"org.mozilla.fennec_aurora" to 0,
|
"org.mozilla.fennec_aurora" to 0,
|
||||||
"com.opera.mini.native" to 0,
|
"com.opera.mini.native" to 0,
|
||||||
"com.opera.mini.native.beta" to 0,
|
"com.opera.mini.native.beta" to 0,
|
||||||
"com.opera.touch" to 0
|
"com.opera.touch" to 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@@ -162,7 +162,7 @@ private val FLAKY_BROWSERS = listOf(
|
|||||||
"com.android.chrome",
|
"com.android.chrome",
|
||||||
"com.chrome.beta",
|
"com.chrome.beta",
|
||||||
"com.chrome.canary",
|
"com.chrome.canary",
|
||||||
"com.chrome.dev"
|
"com.chrome.dev",
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class BrowserAutofillSupportLevel {
|
enum class BrowserAutofillSupportLevel {
|
||||||
@@ -170,7 +170,7 @@ enum class BrowserAutofillSupportLevel {
|
|||||||
FlakyFill,
|
FlakyFill,
|
||||||
PasswordFill,
|
PasswordFill,
|
||||||
GeneralFill,
|
GeneralFill,
|
||||||
GeneralFillAndSave
|
GeneralFillAndSave,
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
@@ -33,19 +33,19 @@ class FormField(
|
|||||||
|
|
||||||
private val HINTS_USERNAME = listOf(
|
private val HINTS_USERNAME = listOf(
|
||||||
HintConstants.AUTOFILL_HINT_USERNAME,
|
HintConstants.AUTOFILL_HINT_USERNAME,
|
||||||
HintConstants.AUTOFILL_HINT_NEW_USERNAME
|
HintConstants.AUTOFILL_HINT_NEW_USERNAME,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val HINTS_NEW_PASSWORD = listOf(
|
private val HINTS_NEW_PASSWORD = listOf(
|
||||||
HintConstants.AUTOFILL_HINT_NEW_PASSWORD
|
HintConstants.AUTOFILL_HINT_NEW_PASSWORD,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val HINTS_PASSWORD = HINTS_NEW_PASSWORD + listOf(
|
private val HINTS_PASSWORD = HINTS_NEW_PASSWORD + listOf(
|
||||||
HintConstants.AUTOFILL_HINT_PASSWORD
|
HintConstants.AUTOFILL_HINT_PASSWORD,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val HINTS_OTP = listOf(
|
private val HINTS_OTP = listOf(
|
||||||
HintConstants.AUTOFILL_HINT_SMS_OTP
|
HintConstants.AUTOFILL_HINT_SMS_OTP,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@@ -54,7 +54,7 @@ class FormField(
|
|||||||
HintConstants.AUTOFILL_HINT_NAME,
|
HintConstants.AUTOFILL_HINT_NAME,
|
||||||
HintConstants.AUTOFILL_HINT_PERSON_NAME,
|
HintConstants.AUTOFILL_HINT_PERSON_NAME,
|
||||||
HintConstants.AUTOFILL_HINT_PHONE,
|
HintConstants.AUTOFILL_HINT_PHONE,
|
||||||
HintConstants.AUTOFILL_HINT_PHONE_NUMBER
|
HintConstants.AUTOFILL_HINT_PHONE_NUMBER,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val ANDROID_TEXT_FIELD_CLASS_NAMES = listOf(
|
private val ANDROID_TEXT_FIELD_CLASS_NAMES = listOf(
|
||||||
@@ -62,7 +62,7 @@ class FormField(
|
|||||||
"android.widget.AutoCompleteTextView",
|
"android.widget.AutoCompleteTextView",
|
||||||
"androidx.appcompat.widget.AppCompatEditText",
|
"androidx.appcompat.widget.AppCompatEditText",
|
||||||
"android.support.v7.widget.AppCompatEditText",
|
"android.support.v7.widget.AppCompatEditText",
|
||||||
"com.google.android.material.textfield.TextInputEditText"
|
"com.google.android.material.textfield.TextInputEditText",
|
||||||
)
|
)
|
||||||
|
|
||||||
private const val ANDROID_WEB_VIEW_CLASS_NAME = "android.webkit.WebView"
|
private const val ANDROID_WEB_VIEW_CLASS_NAME = "android.webkit.WebView"
|
||||||
@@ -75,15 +75,24 @@ class FormField(
|
|||||||
InputType.TYPE_CLASS_TEXT -> typeVariation in listOf(
|
InputType.TYPE_CLASS_TEXT -> typeVariation in listOf(
|
||||||
InputType.TYPE_TEXT_VARIATION_PASSWORD,
|
InputType.TYPE_TEXT_VARIATION_PASSWORD,
|
||||||
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD,
|
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD,
|
||||||
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD
|
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD,
|
||||||
)
|
)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val HTML_INPUT_FIELD_TYPES_USERNAME = listOf("email", "tel", "text")
|
private val HTML_INPUT_FIELD_TYPES_USERNAME = listOf(
|
||||||
private val HTML_INPUT_FIELD_TYPES_PASSWORD = listOf("password")
|
"email",
|
||||||
private val HTML_INPUT_FIELD_TYPES_OTP = listOf("tel", "text")
|
"tel",
|
||||||
|
"text",
|
||||||
|
)
|
||||||
|
private val HTML_INPUT_FIELD_TYPES_PASSWORD = listOf(
|
||||||
|
"password",
|
||||||
|
)
|
||||||
|
private val HTML_INPUT_FIELD_TYPES_OTP = listOf(
|
||||||
|
"tel",
|
||||||
|
"text",
|
||||||
|
)
|
||||||
private val HTML_INPUT_FIELD_TYPES_FILLABLE =
|
private val HTML_INPUT_FIELD_TYPES_FILLABLE =
|
||||||
(HTML_INPUT_FIELD_TYPES_USERNAME + HTML_INPUT_FIELD_TYPES_PASSWORD + HTML_INPUT_FIELD_TYPES_OTP).toSet().toList()
|
(HTML_INPUT_FIELD_TYPES_USERNAME + HTML_INPUT_FIELD_TYPES_PASSWORD + HTML_INPUT_FIELD_TYPES_OTP).toSet().toList()
|
||||||
|
|
||||||
@@ -95,20 +104,27 @@ class FormField(
|
|||||||
"url_field", // Opera address bar
|
"url_field", // Opera address bar
|
||||||
"location_bar_edit_text", // Samsung address bar
|
"location_bar_edit_text", // Samsung address bar
|
||||||
"search", "find", "captcha",
|
"search", "find", "captcha",
|
||||||
"postal" // Prevent postal code fields from being mistaken for OTP fields
|
"postal", // Prevent postal code fields from being mistaken for OTP fields
|
||||||
|
|
||||||
)
|
)
|
||||||
private val PASSWORD_HEURISTIC_TERMS = listOf(
|
private val PASSWORD_HEURISTIC_TERMS = listOf(
|
||||||
"pass", "pswd", "pwd"
|
"pass",
|
||||||
|
"pswd",
|
||||||
|
"pwd",
|
||||||
)
|
)
|
||||||
private val USERNAME_HEURISTIC_TERMS = listOf(
|
private val USERNAME_HEURISTIC_TERMS = listOf(
|
||||||
"alias", "e-mail", "email", "login", "user"
|
"alias",
|
||||||
|
"e-mail",
|
||||||
|
"email",
|
||||||
|
"login",
|
||||||
|
"user",
|
||||||
)
|
)
|
||||||
private val OTP_HEURISTIC_TERMS = listOf(
|
private val OTP_HEURISTIC_TERMS = listOf(
|
||||||
"einmal", "otp"
|
"einmal",
|
||||||
|
"otp",
|
||||||
)
|
)
|
||||||
private val OTP_WEAK_HEURISTIC_TERMS = listOf(
|
private val OTP_WEAK_HEURISTIC_TERMS = listOf(
|
||||||
"code"
|
"code",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ class OreoAutofillService : AutofillService() {
|
|||||||
"com.android.settings.intelligence",
|
"com.android.settings.intelligence",
|
||||||
"com.android.systemui",
|
"com.android.systemui",
|
||||||
"com.oneplus.applocker",
|
"com.oneplus.applocker",
|
||||||
"org.sufficientlysecure.keychain"
|
"org.sufficientlysecure.keychain",
|
||||||
)
|
)
|
||||||
|
|
||||||
private const val DISABLE_AUTOFILL_DURATION_MS = 1000 * 60 * 60 * 24L
|
private const val DISABLE_AUTOFILL_DURATION_MS = 1000 * 60 * 60 * 24L
|
||||||
|
@@ -11,7 +11,6 @@ import android.text.InputType
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.activity.result.IntentSenderRequest
|
import androidx.activity.result.IntentSenderRequest
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
|
import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
|
||||||
@@ -59,7 +58,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
|
|||||||
private var oldCategory: String? = null
|
private var oldCategory: String? = null
|
||||||
private var copy: Boolean = false
|
private var copy: Boolean = false
|
||||||
|
|
||||||
private val userInteractionRequiredResult: ActivityResultLauncher<IntentSenderRequest> = registerForActivityResult(StartIntentSenderForResult()) { result ->
|
private val userInteractionRequiredResult = registerForActivityResult(StartIntentSenderForResult()) { result ->
|
||||||
if (result.data == null) {
|
if (result.data == null) {
|
||||||
setResult(RESULT_CANCELED, null)
|
setResult(RESULT_CANCELED, null)
|
||||||
finish()
|
finish()
|
||||||
|
@@ -217,7 +217,7 @@ class SshjConfig : ConfigImpl() {
|
|||||||
ECDHNistP.Factory521(),
|
ECDHNistP.Factory521(),
|
||||||
ECDHNistP.Factory384(),
|
ECDHNistP.Factory384(),
|
||||||
ECDHNistP.Factory256(),
|
ECDHNistP.Factory256(),
|
||||||
DHGexSHA256.Factory()
|
DHGexSHA256.Factory(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ class SshjConfig : ConfigImpl() {
|
|||||||
SignatureECDSA.Factory384(),
|
SignatureECDSA.Factory384(),
|
||||||
SignatureECDSA.Factory521(),
|
SignatureECDSA.Factory521(),
|
||||||
SignatureRSA.Factory(),
|
SignatureRSA.Factory(),
|
||||||
FactoryCERT()
|
FactoryCERT(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ class SshjConfig : ConfigImpl() {
|
|||||||
PKCS8KeyFile.Factory(),
|
PKCS8KeyFile.Factory(),
|
||||||
PKCS5KeyFile.Factory(),
|
PKCS5KeyFile.Factory(),
|
||||||
OpenSSHKeyFile.Factory(),
|
OpenSSHKeyFile.Factory(),
|
||||||
PuTTYKeyFile.Factory()
|
PuTTYKeyFile.Factory(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ class SshjConfig : ConfigImpl() {
|
|||||||
cipherFactories = listOf(
|
cipherFactories = listOf(
|
||||||
BlockCiphers.AES128CTR(),
|
BlockCiphers.AES128CTR(),
|
||||||
BlockCiphers.AES192CTR(),
|
BlockCiphers.AES192CTR(),
|
||||||
BlockCiphers.AES256CTR()
|
BlockCiphers.AES256CTR(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,13 +260,13 @@ class SshjConfig : ConfigImpl() {
|
|||||||
Macs.HMACSHA2256(),
|
Macs.HMACSHA2256(),
|
||||||
Macs.HMACSHA2256Etm(),
|
Macs.HMACSHA2256Etm(),
|
||||||
Macs.HMACSHA2512(),
|
Macs.HMACSHA2512(),
|
||||||
Macs.HMACSHA2512Etm()
|
Macs.HMACSHA2512Etm(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initCompressionFactories() {
|
private fun initCompressionFactories() {
|
||||||
compressionFactories = listOf(
|
compressionFactories = listOf(
|
||||||
NoneCompression.Factory()
|
NoneCompression.Factory(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,14 +22,13 @@ object RandomPasswordGenerator {
|
|||||||
* set, the password will not contain any symbols.
|
* set, the password will not contain any symbols.
|
||||||
* - [PasswordGenerator.NO_AMBIGUOUS]: If set, the password will not contain any ambiguous
|
* - [PasswordGenerator.NO_AMBIGUOUS]: If set, the password will not contain any ambiguous
|
||||||
* characters.
|
* characters.
|
||||||
* - [PasswordGenerator.NO_VOWELS]: If set, the password will not contain any vowels.
|
|
||||||
*/
|
*/
|
||||||
fun generate(targetLength: Int, pwFlags: Int): String? {
|
fun generate(targetLength: Int, pwFlags: Int): String? {
|
||||||
val bank = listOfNotNull(
|
val bank = listOfNotNull(
|
||||||
PasswordGenerator.DIGITS_STR.takeIf { pwFlags hasFlag PasswordGenerator.DIGITS },
|
PasswordGenerator.DIGITS_STR.takeIf { pwFlags hasFlag PasswordGenerator.DIGITS },
|
||||||
PasswordGenerator.UPPERS_STR.takeIf { pwFlags hasFlag PasswordGenerator.UPPERS },
|
PasswordGenerator.UPPERS_STR.takeIf { pwFlags hasFlag PasswordGenerator.UPPERS },
|
||||||
PasswordGenerator.LOWERS_STR.takeIf { pwFlags hasFlag PasswordGenerator.LOWERS },
|
PasswordGenerator.LOWERS_STR.takeIf { pwFlags hasFlag PasswordGenerator.LOWERS },
|
||||||
PasswordGenerator.SYMBOLS_STR.takeIf { pwFlags hasFlag PasswordGenerator.SYMBOLS }
|
PasswordGenerator.SYMBOLS_STR.takeIf { pwFlags hasFlag PasswordGenerator.SYMBOLS },
|
||||||
).joinToString("")
|
).joinToString("")
|
||||||
|
|
||||||
var password = ""
|
var password = ""
|
||||||
|
@@ -54,6 +54,7 @@ subprojects {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
|
freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
|
||||||
|
languageVersion = "1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,15 +6,15 @@
|
|||||||
object Plugins {
|
object Plugins {
|
||||||
|
|
||||||
const val agp = "com.android.tools.build:gradle:4.0.1"
|
const val agp = "com.android.tools.build:gradle:4.0.1"
|
||||||
const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
|
const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0-rc"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Dependencies {
|
object Dependencies {
|
||||||
object Kotlin {
|
object Kotlin {
|
||||||
object Coroutines {
|
object Coroutines {
|
||||||
|
|
||||||
const val android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
|
const val android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8-1.4.0-rc"
|
||||||
const val core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
|
const val core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8-1.4.0-rc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user