From 4666a2fa51399b6ffb27d41ca7bbfb27702b013a Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Tue, 21 Jun 2022 23:35:19 -0300 Subject: [PATCH] New Release! [All versions] Now the app supports using plaintext passwords for authentication, as some subsonic implementations need it to work. Please try not to use this on unsecure connections (i.e. http://) as the password travels unencrypted through the network. Closes #2. Thanks @epoupon --- .../tech/logica10/soniclair/BackendPlugin.kt | 4 +++- .../logica10/soniclair/KeyValueStorage.kt | 2 +- .../tech/logica10/soniclair/SubsonicClient.kt | 19 ++++++++++--------- .../tech/logica10/soniclair/models/Account.kt | 2 +- .../logica10/soniclair/models/BasicParams.kt | 18 +++++++++++++----- .../tech/logica10/soniclair/models/Context.kt | 2 +- .../soniclair/models/SubsonicResponse.kt | 2 +- src/Components/PlayTest.tsx | 12 ++++++++++-- 8 files changed, 40 insertions(+), 21 deletions(-) diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/BackendPlugin.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/BackendPlugin.kt index ab914df..49d33a6 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/BackendPlugin.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/BackendPlugin.kt @@ -163,11 +163,13 @@ class BackendPlugin : Plugin(), IBroadcastObserver { val username = data.getString("username") ?: throw ParameterException("username") val password = data.getString("password") ?: throw Exception("password") val url = data.getString("url") ?: throw Exception("url") + val usePlaintext = data.getBoolean("usePlaintext") try { val account = subsonicClient!!.login( username, password, - url + url, + usePlaintext ) setActiveAccount(account) call.resolve(okResponse(account)) diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/KeyValueStorage.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/KeyValueStorage.kt index 0ecd4c2..d22bc71 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/KeyValueStorage.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/KeyValueStorage.kt @@ -35,7 +35,7 @@ class KeyValueStorage { val account: Account = Gson().fromJson(activeAccount, Account::class.java) account } catch (exception: Exception) { - Account(null, "", "", "") + Account(null, "", "", "", false) } } diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/SubsonicClient.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/SubsonicClient.kt index 34631db..e1f1a3d 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/SubsonicClient.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/SubsonicClient.kt @@ -6,7 +6,6 @@ package tech.logica10.soniclair import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.ConnectivityManager -import android.net.Network import android.net.NetworkCapabilities import android.net.Uri import android.support.v4.media.MediaBrowserCompat @@ -40,7 +39,7 @@ import java.util.concurrent.TimeUnit class SubsonicClient(var initialAccount: Account) { companion object { - var account: Account = Account(null, "", "", "") + var account: Account = Account(null, "", "", "", false) var spotifyToken: String = "" var downloadQueue: MutableList = mutableListOf() var downloadQueueForce: HashMap = HashMap() @@ -75,11 +74,12 @@ class SubsonicClient(var initialAccount: Account) { BigInteger(1, md.digest(saltedPassword.toByteArray())).toString(16).padStart(32, '0') return BasicParams( account.username ?: "", - hash, - salt, + if(account.usePlaintext) null else hash, + if(account.usePlaintext) null else salt, "1.16.1", "soniclair", "json", + if(account.usePlaintext) account.password else null ) } @@ -646,6 +646,7 @@ class SubsonicClient(var initialAccount: Account) { uriBuilder.appendQueryParameter(key, map[key]) } uriBuilder.appendQueryParameter("id", song.id) + uriBuilder.appendQueryParameter("estimateContentLength", "true") if (KeyValueStorage.getSettings().transcoding != "" && connectivityManager.getNetworkCapabilities( @@ -654,7 +655,6 @@ class SubsonicClient(var initialAccount: Account) { ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) == false ) { uriBuilder.appendQueryParameter("format", KeyValueStorage.getSettings().transcoding) - uriBuilder.appendQueryParameter("estimateContentLength", "true") } return uriBuilder.build().toString() @@ -678,7 +678,7 @@ class SubsonicClient(var initialAccount: Account) { )!!.song } - fun login(username: String, password: String, url: String): Account { + fun login(username: String, password: String, url: String, usePlaintext: Boolean): Account { val salt = "abcd1234" val saltedPassword = "${password}${salt}" val md = MessageDigest.getInstance("MD5") @@ -686,11 +686,12 @@ class SubsonicClient(var initialAccount: Account) { BigInteger(1, md.digest(saltedPassword.toByteArray())).toString(16).padStart(32, '0') val basicParams = BasicParams( username, - hash, - salt, + if(usePlaintext) null else hash, + if(usePlaintext) null else salt, "1.16.1", "soniclair", "json", + if(usePlaintext) password else null ) val uriBuilder = Uri.parse(url).buildUpon() .appendPath("rest") @@ -715,7 +716,7 @@ class SubsonicClient(var initialAccount: Account) { if (ret.status != "ok") { throw Exception(ret.error?.message) } - account = Account(username, password, url, ret.type) + account = Account(username, password, url, ret.type ?: "Unknown Server", usePlaintext) KeyValueStorage.setActiveAccount(account) val accounts = KeyValueStorage.getAccounts() val exists = accounts.filter { it.url == url }.size == 1 diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/models/Account.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/models/Account.kt index 2dd00a8..a7974d1 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/models/Account.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/models/Account.kt @@ -1,4 +1,4 @@ package tech.logica10.soniclair.models -class Account(val username: String?, val password: String, val url: String, var type: String) +class Account(val username: String?, val password: String, val url: String, var type: String, var usePlaintext: Boolean) diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/models/BasicParams.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/models/BasicParams.kt index c6d7815..866b689 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/models/BasicParams.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/models/BasicParams.kt @@ -2,17 +2,25 @@ package tech.logica10.soniclair.models class BasicParams( val u: String, - val t: String, - val s: String, + val t: String?, + val s: String?, val v: String, val c: String, - val f: String + val f: String, + val p: String?, ) { fun asMap(): HashMap { val ret = HashMap() ret["u"] = u - ret["t"] = t - ret["s"] = s + if (t != null) { + ret["t"] = t + } + if (s != null) { + ret["s"] = s + } + if (p != null) { + ret["p"] = p + } ret["v"] = v ret["c"] = c ret["f"] = f diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/models/Context.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/models/Context.kt index 9dc50bd..43a08fc 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/models/Context.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/models/Context.kt @@ -2,5 +2,5 @@ package tech.logica10.soniclair.models class Context( val accounts: List = emptyList(), - val activeAccount: Account = Account(null, "", "", ""), + val activeAccount: Account = Account(null, "", "", "", false), ) \ No newline at end of file diff --git a/android/app/src/main/kotlin/tech/logica10/soniclair/models/SubsonicResponse.kt b/android/app/src/main/kotlin/tech/logica10/soniclair/models/SubsonicResponse.kt index 84b13cc..0cac77b 100644 --- a/android/app/src/main/kotlin/tech/logica10/soniclair/models/SubsonicResponse.kt +++ b/android/app/src/main/kotlin/tech/logica10/soniclair/models/SubsonicResponse.kt @@ -3,7 +3,7 @@ package tech.logica10.soniclair.models open class SubsonicResponse { val serverVersion: String = "" val status: String = "" - val type: String = "" + val type: String? = "" val version: String = "" val error: SubsonicError? = null } \ No newline at end of file diff --git a/src/Components/PlayTest.tsx b/src/Components/PlayTest.tsx index bc7a7e3..8c1e1f3 100644 --- a/src/Components/PlayTest.tsx +++ b/src/Components/PlayTest.tsx @@ -270,10 +270,18 @@ export default function PlayTest() { className="form-check-input" type="checkbox" id="flexSwitchCheckDefault" - {...register("usePlaintext", { required: true })} + {...register("usePlaintext")} /> - + + {errors && errors.url && ( +
+ {errors.usePlaintext?.message} +
+ )}