2023-08-31 12:20:06 +02:00
|
|
|
using System;
|
2022-08-30 15:42:25 +02:00
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using NSubstitute;
|
2021-07-12 21:31:46 +02:00
|
|
|
using NUnit.Framework;
|
|
|
|
using Plugin.BLE.Abstractions;
|
|
|
|
using Plugin.BLE.Abstractions.Contracts;
|
|
|
|
using TINK.Services.BluetoothLock.BLE;
|
2022-08-30 15:42:25 +02:00
|
|
|
using TINK.Services.BluetoothLock.Exception;
|
|
|
|
using TINK.Services.BluetoothLock.Tdo;
|
2021-07-12 21:31:46 +02:00
|
|
|
|
|
|
|
namespace TestTINKLib.Fixtures.ObjectTests.Settings.BluetoothLock
|
|
|
|
{
|
2022-09-06 16:08:19 +02:00
|
|
|
[TestFixture]
|
|
|
|
public class TestLockIt
|
|
|
|
{
|
|
|
|
[Test]
|
|
|
|
public void TestAuthenticate_InvalidSeed()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var ciper = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { 0 },
|
|
|
|
K_u = new byte[] { 1 }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
|
|
|
|
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
|
|
|
|
|
|
|
Assert.That(() => LockItEventBased.Authenticate(device, authInfo, adapter, ciper), Throws.InstanceOf<AuthKeyException>());
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void TestAuthenticate_InvalidAuthKey()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var ciper = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { (byte)'t', (byte)'q', (byte)'2', (byte)'n', (byte)'c', (byte)'A', (byte)'I', (byte)'v', (byte)'M', (byte)'t', (byte)'h', (byte)'g', (byte)'x', (byte)'a', (byte)'z', (byte)'B' },
|
|
|
|
K_u = new byte[] { }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
|
|
|
|
|
|
|
Assert.That(async () => { await LockItEventBased.Authenticate(device, authInfo, adapter, ciper); }, Throws.InstanceOf<AuthKeyException>());
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void TestAuthenticate_Invalidated()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
var auth = Substitute.For<ICharacteristic>();
|
|
|
|
var lockControl = Substitute.For<IService>();
|
|
|
|
var state = Substitute.For<ICharacteristic>();
|
|
|
|
var activateLock = Substitute.For<ICharacteristic>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { (byte)'z', (byte)'D', (byte)'G', (byte)'x', (byte)'q', (byte)'M', (byte)'f', (byte)'A', (byte)'F', (byte)'q', (byte)'g', (byte)'N', (byte)'V', (byte)'r', (byte)'N', (byte)'Y' },
|
|
|
|
K_u = new byte[] { 1 }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
// Calls related to Authenticate functionality.
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
|
|
|
|
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true));
|
|
|
|
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[8]));
|
|
|
|
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
|
|
|
|
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(true);
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
|
|
|
|
|
|
|
// Call authenticate to invalidate seed
|
|
|
|
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
|
|
|
|
|
|
|
|
// Authenticate again to
|
|
|
|
var execption = Assert.Throws<AggregateException>(() => { var dummy = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result; });
|
|
|
|
|
|
|
|
Assert.That(
|
|
|
|
execption.InnerExceptions[0].Message,
|
|
|
|
Does.Contain("Seed 122,68,71,120,113,77,102,65,70,113,103,78,86,114,78,89 was already used."));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void TestAuthenticate_GetAuthCharacteristicThrowsException()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
var auth = Substitute.For<ICharacteristic>();
|
|
|
|
var lockControl = Substitute.For<IService>();
|
|
|
|
var state = Substitute.For<ICharacteristic>();
|
|
|
|
var activateLock = Substitute.For<ICharacteristic>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
|
|
|
K_u = new byte[] { 1 }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
// Calls related to Authenticate functionality.
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
|
|
|
|
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult((ICharacteristic)null));
|
|
|
|
|
|
|
|
// Authenticate again to
|
|
|
|
Assert.That(() => LockItEventBased.Authenticate(device, authInfo, adapter, cipher), Throws.InstanceOf<CoundntGetCharacteristicException>());
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public async Task TestAuthenticate_GetLockState_Closed()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
var auth = Substitute.For<ICharacteristic>();
|
|
|
|
var lockControl = Substitute.For<IService>();
|
|
|
|
var state = Substitute.For<ICharacteristic>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
|
|
|
K_u = new byte[] { 1 }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
// Calls related to Authenticate functionality.
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
|
|
|
|
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true));
|
|
|
|
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[8]));
|
|
|
|
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
|
|
|
|
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(true);
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
|
|
|
// Calls related to get lock state.
|
|
|
|
|
|
|
|
// Call authenticate to invalidate seed
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(state));
|
|
|
|
state.ReadAsync(Arg.Any<CancellationToken>()).Returns(new byte[] { 1 });
|
|
|
|
|
|
|
|
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
|
|
|
|
|
|
|
|
Assert.That((await lockIt.GetLockStateAsync()).State, Is.EqualTo(LockitLockingState.Closed));
|
|
|
|
}
|
|
|
|
|
2023-08-31 12:20:06 +02:00
|
|
|
[Test]
|
|
|
|
public async Task TestAuthenticate_GetLockState_UndefinedState()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
var auth = Substitute.For<ICharacteristic>();
|
|
|
|
var lockControl = Substitute.For<IService>();
|
|
|
|
var state = Substitute.For<ICharacteristic>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
|
|
|
|
K_u = new byte[] { 1 }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
// Calls related to Authenticate functionality.
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
|
|
|
|
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true));
|
|
|
|
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[8]));
|
|
|
|
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
|
|
|
|
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(true);
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
|
|
|
// Calls related to get lock state.
|
|
|
|
|
|
|
|
// Call authenticate to invalidate seed
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(state));
|
|
|
|
state.ReadAsync(Arg.Any<CancellationToken>()).Returns(new byte[] { 99 }); // This value should never be returned from ILockit.
|
|
|
|
|
|
|
|
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
|
|
|
|
|
|
|
|
Assert.That((await lockIt.GetLockStateAsync()).State, Is.Null);
|
|
|
|
}
|
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
[Test]
|
|
|
|
public void TestAuthenticate_GetLockState_GetStateCharacteristicThrowsException()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
|
|
|
var cipher = Substitute.For<TINK.Model.Device.ICipher>();
|
|
|
|
var auth = Substitute.For<ICharacteristic>();
|
|
|
|
var lockControl = Substitute.For<IService>();
|
|
|
|
|
|
|
|
var authInfo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
K_seed = new byte[] { (byte)'y', (byte)'D', (byte)'G', (byte)'x', (byte)'q', (byte)'M', (byte)'f', (byte)'A', (byte)'F', (byte)'q', (byte)'g', (byte)'N', (byte)'V', (byte)'r', (byte)'N', (byte)'Y' },
|
|
|
|
K_u = new byte[] { 1 }
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
// Calls related to Authenticate functionality.
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
|
|
|
|
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true));
|
|
|
|
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[8]));
|
|
|
|
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
|
|
|
|
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
|
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(true);
|
|
|
|
device.State.Returns(DeviceState.Connected);
|
|
|
|
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
|
|
|
|
|
|
|
// Calls related to get lock state.
|
|
|
|
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult((ICharacteristic)null));
|
|
|
|
|
|
|
|
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
|
|
|
|
|
|
|
|
Assert.That(async () => (await lockIt.GetLockStateAsync()).State, Throws.InstanceOf<CoundntGetCharacteristicException>());
|
|
|
|
}
|
|
|
|
}
|
2021-07-12 21:31:46 +02:00
|
|
|
}
|