1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-25 11:26:47 +01:00

Xiaomi: Unify encrypted and plaintext logic

This commit is contained in:
José Rebelo 2023-12-02 11:25:32 +00:00
parent ba0ca1de75
commit ec050d7a4f
13 changed files with 190 additions and 314 deletions

View File

@ -17,6 +17,8 @@
package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
import android.app.Activity;
import android.bluetooth.le.ScanFilter;
import android.os.ParcelUuid;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -25,7 +27,10 @@ import org.apache.commons.lang3.ArrayUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
import nodomain.freeyourgadget.gadgetbridge.GBException;
@ -49,9 +54,41 @@ import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.SleepRespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiBleUuids;
import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl.WorkoutSummaryParser;
public abstract class XiaomiCoordinator extends AbstractBLEDeviceCoordinator {
// On plaintext devices, user id is used as auth key - numeric
private static final Pattern AUTH_KEY_PATTERN = Pattern.compile("^[0-9]+$");
@NonNull
@Override
public Collection<? extends ScanFilter> createBLEScanFilters() {
final List<ScanFilter> filters = new ArrayList<>();
for (final UUID uuid : XiaomiBleUuids.UUIDS.keySet()) {
final ParcelUuid service = new ParcelUuid(uuid);
final ScanFilter filter = new ScanFilter.Builder().setServiceUuid(service).build();
filters.add(filter);
}
return filters;
}
@NonNull
@Override
public Class<? extends DeviceSupport> getDeviceSupportClass() {
return XiaomiSupport.class;
}
@Override
public boolean validateAuthKey(final String authKey) {
final byte[] authKeyBytes = authKey.trim().getBytes();
// At this point we don't know if it's encrypted or not, so let's accept both:
return authKeyBytes.length == 32 || (authKey.startsWith("0x") && authKeyBytes.length == 34)
|| AUTH_KEY_PATTERN.matcher(authKey.trim()).matches();
}
@Override
protected void deleteDevice(@NonNull final GBDevice gbDevice,
@NonNull final Device device,

View File

@ -1,50 +0,0 @@
/* Copyright (C) 2023 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
import android.bluetooth.le.ScanFilter;
import android.os.ParcelUuid;
import androidx.annotation.NonNull;
import java.util.Collection;
import java.util.Collections;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiEncryptedSupport;
public abstract class XiaomiEncryptedCoordinator extends XiaomiCoordinator {
@NonNull
@Override
public Collection<? extends ScanFilter> createBLEScanFilters() {
final ParcelUuid service = new ParcelUuid(XiaomiEncryptedSupport.UUID_SERVICE_XIAOMI_FE95);
final ScanFilter filter = new ScanFilter.Builder().setServiceUuid(service).build();
return Collections.singletonList(filter);
}
@NonNull
@Override
public Class<? extends DeviceSupport> getDeviceSupportClass() {
return XiaomiEncryptedSupport.class;
}
@Override
public boolean validateAuthKey(final String authKey) {
final byte[] authKeyBytes = authKey.trim().getBytes();
return authKeyBytes.length == 32 || (authKey.startsWith("0x") && authKeyBytes.length == 34);
}
}

View File

@ -1,53 +0,0 @@
/* Copyright (C) 2023 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
import android.bluetooth.le.ScanFilter;
import android.os.ParcelUuid;
import androidx.annotation.NonNull;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiPlaintextSupport;
public abstract class XiaomiPlaintextCoordinator extends XiaomiCoordinator {
// user id is used as auth key - numeric
private static final Pattern AUTH_KEY_PATTERN = Pattern.compile("^[0-9]+$");
@NonNull
@Override
public Collection<? extends ScanFilter> createBLEScanFilters() {
final ParcelUuid service = new ParcelUuid(XiaomiPlaintextSupport.UUID_SERVICE);
final ScanFilter filter = new ScanFilter.Builder().setServiceUuid(service).build();
return Collections.singletonList(filter);
}
@NonNull
@Override
public Class<? extends DeviceSupport> getDeviceSupportClass() {
return XiaomiPlaintextSupport.class;
}
@Override
public boolean validateAuthKey(final String authKey) {
return AUTH_KEY_PATTERN.matcher(authKey.trim()).matches();
}
}

View File

@ -26,10 +26,10 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiEncryptedCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiInstallHandler;
public class MiBand7ProCoordinator extends XiaomiEncryptedCoordinator {
public class MiBand7ProCoordinator extends XiaomiCoordinator {
@Override
public boolean isExperimental() {
return true;

View File

@ -25,10 +25,10 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiEncryptedCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiInstallHandler;
public class MiBand8Coordinator extends XiaomiEncryptedCoordinator {
public class MiBand8Coordinator extends XiaomiCoordinator {
@Override
public boolean isExperimental() {
return true;

View File

@ -25,11 +25,11 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiInstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiPlaintextCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class MiWatchLiteCoordinator extends XiaomiPlaintextCoordinator {
public class MiWatchLiteCoordinator extends XiaomiCoordinator {
@Override
public boolean isExperimental() {
return true;

View File

@ -25,11 +25,11 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiEncryptedCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiInstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class RedmiWatch3ActiveCoordinator extends XiaomiEncryptedCoordinator {
public class RedmiWatch3ActiveCoordinator extends XiaomiCoordinator {
@Override
public boolean isExperimental() {
return true;

View File

@ -25,10 +25,10 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiEncryptedCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiInstallHandler;
public class XiaomiWatchS1ActiveCoordinator extends XiaomiEncryptedCoordinator {
public class XiaomiWatchS1ActiveCoordinator extends XiaomiCoordinator {
@Override
public int getDeviceNameResource() {

View File

@ -94,11 +94,11 @@ public class XiaomiAuthService extends AbstractXiaomiService {
getSupport().sendCommand(builder, buildNonceCommand(nonce));
}
protected void startClearTextHandshake(final TransactionBuilder builder, String userId) {
protected void startClearTextHandshake(final TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getSupport().getDevice(), GBDevice.State.AUTHENTICATING, getSupport().getContext()));
final XiaomiProto.Auth auth = XiaomiProto.Auth.newBuilder()
.setUserId(userId)
.setUserId(getUserId(getSupport().getDevice()))
.build();
final XiaomiProto.Command command = XiaomiProto.Command.newBuilder()
@ -130,7 +130,7 @@ public class XiaomiAuthService extends AbstractXiaomiService {
final TransactionBuilder builder = getSupport().createTransactionBuilder("auth step 2");
// TODO use sendCommand
builder.write(
getSupport().getCharacteristic(XiaomiEncryptedSupport.UUID_CHARACTERISTIC_XIAOMI_COMMAND_WRITE),
getSupport().getCharacteristic(getSupport().characteristicCommandWrite.getCharacteristicUUID()),
ArrayUtils.addAll(PAYLOAD_HEADER_AUTH, reply.toByteArray())
);
builder.queue(getSupport().getQueue());
@ -301,6 +301,17 @@ public class XiaomiAuthService extends AbstractXiaomiService {
return authKeyBytes;
}
protected static String getUserId(final GBDevice device) {
final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress());
final String authKey = sharedPrefs.getString("authkey", null);
if (StringUtils.isNotBlank(authKey)) {
return authKey;
}
return "0000000000";
}
protected static byte[] hmacSHA256(final byte[] key, final byte[] input) {
try {
final Mac mac = Mac.getInstance("HmacSHA256");

View File

@ -0,0 +1,96 @@
/* Copyright (C) 2023 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class XiaomiBleUuids {
public static final Map<UUID, XiaomiBleUuidSet> UUIDS = new LinkedHashMap<UUID, XiaomiBleUuidSet>() {{
// all encrypted devices seem to share the same characteristics
// Mi Band 8
// Redmi Watch 3 Active
// Xiaomi Watch S1 Active
put(UUID.fromString("0000fe95-0000-1000-8000-00805f9b34fb"), new XiaomiBleUuidSet(
true,
UUID.fromString("00000051-0000-1000-8000-00805f9b34fb"),
UUID.fromString("00000052-0000-1000-8000-00805f9b34fb"),
UUID.fromString("00000053-0000-1000-8000-00805f9b34fb"),
UUID.fromString("00000055-0000-1000-8000-00805f9b34fb")
));
// Mi Watch Lite
put(UUID.fromString("16186f00-0000-1000-8000-00807f9b34fb"), new XiaomiBleUuidSet(
false,
UUID.fromString("16186f01-0000-1000-8000-00807f9b34fb"),
UUID.fromString("16186f02-0000-1000-8000-00807f9b34fb"),
UUID.fromString("16186f03-0000-1000-8000-00807f9b34fb"),
UUID.fromString("16186f04-0000-1000-8000-00807f9b34fb")
));
// Mi Watch Color Sport
put(UUID.fromString("1314f000-1000-9000-7000-301291e21220"), new XiaomiBleUuidSet(
false,
UUID.fromString("1314f005-1000-9000-7000-301291e21220"),
UUID.fromString("1314f001-1000-9000-7000-301291e21220"),
UUID.fromString("1314f002-1000-9000-7000-301291e21220"),
UUID.fromString("1314f007-1000-9000-7000-301291e21220")
));
}};
public static class XiaomiBleUuidSet {
private final boolean encrypted;
private final UUID characteristicCommandRead;
private final UUID characteristicCommandWrite;
private final UUID characteristicActivityData;
private final UUID characteristicDataUpload;
public XiaomiBleUuidSet(final boolean encrypted,
final UUID characteristicCommandRead,
final UUID characteristicCommandWrite,
final UUID characteristicActivityData,
final UUID characteristicDataUpload) {
this.encrypted = encrypted;
this.characteristicCommandRead = characteristicCommandRead;
this.characteristicCommandWrite = characteristicCommandWrite;
this.characteristicActivityData = characteristicActivityData;
this.characteristicDataUpload = characteristicDataUpload;
}
protected boolean isEncrypted() {
return encrypted;
}
protected UUID getCharacteristicCommandRead() {
return characteristicCommandRead;
}
protected UUID getCharacteristicCommandWrite() {
return characteristicCommandWrite;
}
protected UUID getCharacteristicActivityData() {
return characteristicActivityData;
}
protected UUID getCharacteristicDataUpload() {
return characteristicDataUpload;
}
}
}

View File

@ -1,89 +0,0 @@
/* Copyright (C) 2023 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
public class XiaomiEncryptedSupport extends XiaomiSupport {
private static final Logger LOG = LoggerFactory.getLogger(XiaomiEncryptedSupport.class);
public static final String BASE_UUID = "0000%s-0000-1000-8000-00805f9b34fb";
public static final UUID UUID_SERVICE_XIAOMI_FE95 = UUID.fromString((String.format(BASE_UUID, "fe95")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0050 = UUID.fromString((String.format(BASE_UUID, "0050")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_COMMAND_READ = UUID.fromString((String.format(BASE_UUID, "0051")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_COMMAND_WRITE = UUID.fromString((String.format(BASE_UUID, "0052")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_ACTIVITY_DATA = UUID.fromString((String.format(BASE_UUID, "0053")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0054 = UUID.fromString((String.format(BASE_UUID, "0054")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_DATA_UPLOAD = UUID.fromString((String.format(BASE_UUID, "0055")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0056 = UUID.fromString((String.format(BASE_UUID, "0056")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0057 = UUID.fromString((String.format(BASE_UUID, "0057")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0058 = UUID.fromString((String.format(BASE_UUID, "0058")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0059 = UUID.fromString((String.format(BASE_UUID, "0059")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_005A = UUID.fromString((String.format(BASE_UUID, "005a")));
public static final UUID UUID_SERVICE_XIAOMI_FDAB = UUID.fromString((String.format(BASE_UUID, "fdab")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0001 = UUID.fromString((String.format(BASE_UUID, "0001")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0002 = UUID.fromString((String.format(BASE_UUID, "0002")));
public static final UUID UUID_CHARACTERISTIC_XIAOMI_UNKNOWN_0003 = UUID.fromString((String.format(BASE_UUID, "0003")));
public XiaomiEncryptedSupport() {
super();
addSupportedService(GattService.UUID_SERVICE_GENERIC_ACCESS);
addSupportedService(GattService.UUID_SERVICE_GENERIC_ATTRIBUTE);
addSupportedService(GattService.UUID_SERVICE_DEVICE_INFORMATION);
addSupportedService(GattService.UUID_SERVICE_HUMAN_INTERFACE_DEVICE);
addSupportedService(UUID_SERVICE_XIAOMI_FE95);
addSupportedService(UUID_SERVICE_XIAOMI_FDAB);
}
@Override
protected boolean isEncrypted() {
return true;
}
@Override
protected UUID getCharacteristicCommandRead() {
return UUID_CHARACTERISTIC_XIAOMI_COMMAND_READ;
}
@Override
protected UUID getCharacteristicCommandWrite() {
return UUID_CHARACTERISTIC_XIAOMI_COMMAND_WRITE;
}
@Override
protected UUID getCharacteristicActivityData() {
return UUID_CHARACTERISTIC_XIAOMI_ACTIVITY_DATA;
}
@Override
protected UUID getCharacteristicDataUpload() {
return UUID_CHARACTERISTIC_XIAOMI_DATA_UPLOAD;
}
@Override
protected void startAuthentication(final TransactionBuilder builder) {
authService.startEncryptedHandshake(builder);
}
}

View File

@ -1,87 +0,0 @@
/* Copyright (C) 2023 Andreas Shimokawa
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi;
import android.content.SharedPreferences;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
public class XiaomiPlaintextSupport extends XiaomiSupport {
private static final Logger LOG = LoggerFactory.getLogger(XiaomiPlaintextSupport.class);
public static final UUID UUID_SERVICE = UUID.fromString("16186f00-0000-1000-8000-00807f9b34fb");
private static final UUID UUID_CHARACTERISTIC_MAIN_READ = UUID.fromString("16186f01-0000-1000-8000-00807f9b34fb");
private static final UUID UUID_CHARACTERISTIC_MAIN_WRITE = UUID.fromString("16186f02-0000-1000-8000-00807f9b34fb");
private static final UUID UUID_CHARACTERISTIC_ACTIVITY_DATA = UUID.fromString("16186f03-0000-1000-8000-00807f9b34fb");
private static final UUID UUID_CHARACTERISTIC_DATA_UPLOAD = UUID.fromString("16186f04-0000-1000-8000-00807f9b34fb");
private static final UUID UUID_CHARACTERISTIC_UNK5 = UUID.fromString("16186f05-0000-1000-8000-00807f9b34fb");
public XiaomiPlaintextSupport() {
super();
addSupportedService(UUID_SERVICE);
}
@Override
protected boolean isEncrypted() {
return false;
}
@Override
protected UUID getCharacteristicCommandRead() {
return UUID_CHARACTERISTIC_MAIN_READ;
}
@Override
protected UUID getCharacteristicCommandWrite() {
return UUID_CHARACTERISTIC_MAIN_WRITE;
}
@Override
protected UUID getCharacteristicActivityData() {
return UUID_CHARACTERISTIC_ACTIVITY_DATA;
}
@Override
protected UUID getCharacteristicDataUpload() {
return UUID_CHARACTERISTIC_DATA_UPLOAD;
}
@Override
protected void startAuthentication(final TransactionBuilder builder) {
final String userId = getUserId(gbDevice);
authService.startClearTextHandshake(builder, userId);
}
protected static String getUserId(final GBDevice device) {
final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress());
final String authKey = sharedPrefs.getString("authkey", null);
if (StringUtils.isNotBlank(authKey)) {
return authKey;
}
return "0000000000";
}
}

View File

@ -23,6 +23,7 @@ import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.location.Location;
import android.net.Uri;
import android.widget.Toast;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@ -67,7 +68,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.services.Xiao
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public abstract class XiaomiSupport extends AbstractBTLEDeviceSupport {
public class XiaomiSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(XiaomiSupport.class);
protected XiaomiCharacteristic characteristicCommandRead;
@ -105,26 +106,32 @@ public abstract class XiaomiSupport extends AbstractBTLEDeviceSupport {
public XiaomiSupport() {
super(LOG);
for (final UUID uuid : XiaomiBleUuids.UUIDS.keySet()) {
addSupportedService(uuid);
}
}
protected abstract boolean isEncrypted();
protected abstract UUID getCharacteristicCommandRead();
protected abstract UUID getCharacteristicCommandWrite();
protected abstract UUID getCharacteristicActivityData();
protected abstract UUID getCharacteristicDataUpload();
protected abstract void startAuthentication(final TransactionBuilder builder);
@Override
protected final TransactionBuilder initializeDevice(final TransactionBuilder builder) {
final BluetoothGattCharacteristic btCharacteristicCommandRead = getCharacteristic(getCharacteristicCommandRead());
final BluetoothGattCharacteristic btCharacteristicCommandWrite = getCharacteristic(getCharacteristicCommandWrite());
final BluetoothGattCharacteristic btCharacteristicActivityData = getCharacteristic(getCharacteristicActivityData());
final BluetoothGattCharacteristic btCharacteristicDataUpload = getCharacteristic(getCharacteristicDataUpload());
XiaomiBleUuids.XiaomiBleUuidSet uuidSet = null;
for (Map.Entry<UUID, XiaomiBleUuids.XiaomiBleUuidSet> xiaomiUuid : XiaomiBleUuids.UUIDS.entrySet()) {
if (getSupportedServices().contains(xiaomiUuid.getKey())) {
uuidSet = xiaomiUuid.getValue();
break;
}
}
if (uuidSet == null) {
GB.toast(getContext(), "Failed to find known Xiaomi service", Toast.LENGTH_LONG, GB.ERROR);
LOG.warn("Failed to find known Xiaomi service");
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.NOT_CONNECTED, getContext()));
return builder;
}
final BluetoothGattCharacteristic btCharacteristicCommandRead = getCharacteristic(uuidSet.getCharacteristicCommandRead());
final BluetoothGattCharacteristic btCharacteristicCommandWrite = getCharacteristic(uuidSet.getCharacteristicCommandWrite());
final BluetoothGattCharacteristic btCharacteristicActivityData = getCharacteristic(uuidSet.getCharacteristicActivityData());
final BluetoothGattCharacteristic btCharacteristicDataUpload = getCharacteristic(uuidSet.getCharacteristicDataUpload());
// FIXME unsetDynamicState unsets the fw version, which causes problems..
if (getDevice().getFirmwareVersion() == null && mFirmwareVersion != null) {
@ -138,15 +145,15 @@ public abstract class XiaomiSupport extends AbstractBTLEDeviceSupport {
}
this.characteristicCommandRead = new XiaomiCharacteristic(this, btCharacteristicCommandRead, authService);
this.characteristicCommandRead.setEncrypted(isEncrypted());
this.characteristicCommandRead.setEncrypted(uuidSet.isEncrypted());
this.characteristicCommandRead.setHandler(this::handleCommandBytes);
this.characteristicCommandWrite = new XiaomiCharacteristic(this, btCharacteristicCommandWrite, authService);
this.characteristicCommandWrite.setEncrypted(isEncrypted());
this.characteristicCommandWrite.setEncrypted(uuidSet.isEncrypted());
this.characteristicActivityData = new XiaomiCharacteristic(this, btCharacteristicActivityData, authService);
this.characteristicActivityData.setHandler(healthService.getActivityFetcher()::addChunk);
this.characteristicActivityData.setEncrypted(isEncrypted());
this.characteristicActivityData.setEncrypted(uuidSet.isEncrypted());
this.characteristicDataUpload = new XiaomiCharacteristic(this, btCharacteristicDataUpload, authService);
this.characteristicDataUpload.setEncrypted(isEncrypted());
this.characteristicDataUpload.setEncrypted(uuidSet.isEncrypted());
this.characteristicDataUpload.setIncrementNonce(false);
this.dataUploadService.setDataUploadCharacteristic(this.characteristicDataUpload);
@ -159,7 +166,11 @@ public abstract class XiaomiSupport extends AbstractBTLEDeviceSupport {
builder.notify(btCharacteristicActivityData, true);
builder.notify(btCharacteristicDataUpload, true);
startAuthentication(builder);
if (uuidSet.isEncrypted()) {
authService.startEncryptedHandshake(builder);
} else {
authService.startClearTextHandshake(builder);
}
return builder;
}