mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 01:51:47 +00:00
Filter device name
Following the spec: https://invent.kde.org/network/kdeconnect-meta/-/blob/master/protocol.md?ref_type=heads#kdeconnectidentity
This commit is contained in:
parent
e8f7e86b35
commit
440f1d4fa3
@ -183,7 +183,7 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
|
||||
<string name="pair_requested">Pair requested</string>
|
||||
<string name="pair_succeeded">Pair succeeded</string>
|
||||
<string name="pairing_verification_code" translatable="false">🔑 %1s</string>
|
||||
<string name="pairing_request_from">Pairing request from "%1s"</string>
|
||||
<string name="pairing_request_from">Pairing request from \'%1s\'</string>
|
||||
<plurals name="incoming_file_title">Receiving file from %1s>
|
||||
<item quantity="one">Receiving %1$d file from %2$s</item>
|
||||
<item quantity="other">Receiving %1$d files from %2$s</item>
|
||||
|
@ -22,6 +22,7 @@ import android.util.Log
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider
|
||||
import org.kde.kdeconnect.Device
|
||||
import org.kde.kdeconnect.DeviceInfo
|
||||
import org.kde.kdeconnect.DeviceInfo.Companion.fromIdentityPacketAndCert
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
||||
@ -44,6 +45,12 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
|
||||
|
||||
@Throws(CertificateException::class)
|
||||
private fun addLink(identityPacket: NetworkPacket, link: BluetoothLink) {
|
||||
|
||||
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
|
||||
Log.w("KDE/LanLinkProvider", "Invalid identity packet received.")
|
||||
return
|
||||
}
|
||||
|
||||
val deviceId = identityPacket.getString("deviceId")
|
||||
Log.i("BluetoothLinkProvider", "addLink to $deviceId")
|
||||
val oldLink = visibleDevices[deviceId]
|
||||
@ -369,6 +376,13 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
|
||||
socket.close()
|
||||
return
|
||||
}
|
||||
|
||||
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
|
||||
Log.w("KDE/LanLinkProvider", "Invalid identity packet received.")
|
||||
connection.close()
|
||||
return
|
||||
}
|
||||
|
||||
Log.i("BTLinkProvider/Client", "Received identity packet")
|
||||
val myId = DeviceHelper.getDeviceId(context)
|
||||
if (identityPacket.getString("deviceId") == myId) {
|
||||
|
@ -125,6 +125,12 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
|
||||
String message = new String(packet.getData(), Charsets.UTF_8);
|
||||
final NetworkPacket identityPacket = NetworkPacket.unserialize(message);
|
||||
|
||||
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
|
||||
Log.w("KDE/LanLinkProvider", "Invalid identity packet received.");
|
||||
return;
|
||||
}
|
||||
|
||||
final String deviceId = identityPacket.getString("deviceId");
|
||||
if (!identityPacket.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
|
||||
Log.e("KDE/LanLinkProvider", "Expecting an UDP identity packet");
|
||||
@ -192,6 +198,11 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
@WorkerThread
|
||||
private void identityPacketReceived(final NetworkPacket identityPacket, final Socket socket, final LanLink.ConnectionStarted connectionStarted) throws IOException {
|
||||
|
||||
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
|
||||
Log.w("KDE/LanLinkProvider", "Invalid identity packet received.");
|
||||
return;
|
||||
}
|
||||
|
||||
String myId = DeviceHelper.getDeviceId(context);
|
||||
final String deviceId = identityPacket.getString("deviceId");
|
||||
if (deviceId.equals(myId)) {
|
||||
|
@ -10,6 +10,7 @@ import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Base64
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
||||
import org.kde.kdeconnect_tp.R
|
||||
import java.security.cert.Certificate
|
||||
@ -90,7 +91,7 @@ class DeviceInfo(
|
||||
with(identityPacket) {
|
||||
DeviceInfo(
|
||||
id = getString("deviceId"), // Redundant: We could read this from the certificate instead
|
||||
name = getString("deviceName", "unknown"),
|
||||
name = DeviceHelper.filterName(getString("deviceName", "unknown")),
|
||||
type = DeviceType.fromString(getString("deviceType", "desktop")),
|
||||
certificate = certificate,
|
||||
protocolVersion = getInt("protocolVersion"),
|
||||
@ -98,6 +99,11 @@ class DeviceInfo(
|
||||
outgoingCapabilities = getStringSet("outgoingCapabilities")
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isValidIdentityPacket(identityPacket: NetworkPacket): Boolean = with(identityPacket) {
|
||||
DeviceHelper.filterName(getString("deviceName", "")).isNotBlank() && getString("deviceId", "").isNotBlank()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,9 @@ object DeviceHelper {
|
||||
|
||||
private const val DEVICE_DATABASE = "https://storage.googleapis.com/play_public/supported_devices.csv"
|
||||
|
||||
private val NAME_INVALID_CHARACTERS_REGEX = "[\"',;:.!?()\\[\\]<>]".toRegex()
|
||||
const val MAX_DEVICE_NAME_LENGTH = 32
|
||||
|
||||
private val isTablet: Boolean by lazy {
|
||||
val config = Resources.getSystem().configuration
|
||||
//This assumes that the values for the screen sizes are consecutive, so XXLARGE > XLARGE > LARGE
|
||||
@ -119,8 +122,9 @@ object DeviceHelper {
|
||||
}
|
||||
|
||||
fun setDeviceName(context: Context, name: String) {
|
||||
val filteredName = filterName(name)
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
preferences.edit().putString(KEY_DEVICE_NAME_PREFERENCE, name).apply()
|
||||
preferences.edit().putString(KEY_DEVICE_NAME_PREFERENCE, filteredName).apply()
|
||||
}
|
||||
|
||||
fun initializeDeviceId(context: Context) {
|
||||
@ -160,4 +164,7 @@ object DeviceHelper {
|
||||
PluginFactory.getOutgoingCapabilities()
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun filterName(input: String): String = input.replace(NAME_INVALID_CHARACTERS_REGEX, "").take(MAX_DEVICE_NAME_LENGTH)
|
||||
}
|
||||
|
@ -7,14 +7,13 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.text.InputFilter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -33,6 +32,7 @@ import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||
@ -66,6 +66,10 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
renameDevice.setKey(DeviceHelper.KEY_DEVICE_NAME_PREFERENCE);
|
||||
renameDevice.setSelectable(true);
|
||||
renameDevice.setOnBindEditTextListener(TextView::setSingleLine);
|
||||
renameDevice.setOnBindEditTextListener(editText -> editText.setFilters(new InputFilter[] {
|
||||
(source, start, end, dest, dstart, dend) -> DeviceHelper.filterName(source.subSequence(start, end).toString()),
|
||||
new InputFilter.LengthFilter(DeviceHelper.MAX_DEVICE_NAME_LENGTH),
|
||||
}));
|
||||
String deviceName = DeviceHelper.getDeviceName(context);
|
||||
renameDevice.setTitle(R.string.settings_rename);
|
||||
renameDevice.setSummary(deviceName);
|
||||
@ -76,7 +80,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
renameDevice.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String name = (String) newValue;
|
||||
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
if (StringUtils.isBlank(name)) {
|
||||
if (getView() != null) {
|
||||
Snackbar snackbar = Snackbar.make(getView(), R.string.invalid_device_name, Snackbar.LENGTH_LONG);
|
||||
int currentTheme = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
|
@ -132,6 +132,27 @@ public class DeviceTest {
|
||||
assertEquals(di.outgoingCapabilities, np.getStringSet("outgoingCapabilities"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidIdentityPacket() {
|
||||
NetworkPacket np = new NetworkPacket(NetworkPacket.PACKET_TYPE_IDENTITY);
|
||||
assertFalse(DeviceInfo.Companion.isValidIdentityPacket(np));
|
||||
|
||||
String validName = "MyDevice";
|
||||
String validId = "123";
|
||||
np.set("deviceName", validName);
|
||||
np.set("deviceId", validId);
|
||||
assertTrue(DeviceInfo.Companion.isValidIdentityPacket(np));
|
||||
|
||||
np.set("deviceName", " ");
|
||||
assertFalse(DeviceInfo.Companion.isValidIdentityPacket(np));
|
||||
np.set("deviceName", "<><><><><><><><><>"); // Only invalid characters
|
||||
assertFalse(DeviceInfo.Companion.isValidIdentityPacket(np));
|
||||
|
||||
np.set("deviceName", validName);
|
||||
np.set("deviceId", " ");
|
||||
assertFalse(DeviceInfo.Companion.isValidIdentityPacket(np));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeviceType() {
|
||||
assertEquals(DeviceType.PHONE, DeviceType.fromString(DeviceType.PHONE.toString()));
|
||||
|
Loading…
x
Reference in New Issue
Block a user