Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add optional param encryptValue to notify method #1391

Merged
merged 14 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/at_client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## 3.2.1
- feat: add optional param `encryptValue` to notify method
## 3.2.0
- feat: add `allowAll` flag (defaults to false) to AtRpc
## 3.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class AtClientConfig {

/// Represents the at_client version.
/// Must always be the same as the actual version in pubspec.yaml
final String atClientVersion = '3.2.0';
final String atClientVersion = '3.2.1';

/// Represents the client commit log compaction time interval
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ abstract class NotificationService {
true, // this was the behaviour before introducing this parameter
bool checkForFinalDeliveryStatus =
true, // this was the behaviour before introducing this parameter
bool encryptValue = true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the comment // this was the behaviour before introducing this parameter

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Function(NotificationResult)? onSuccess,
Function(NotificationResult)? onError,
Function(NotificationResult)? onSentToSecondary});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ class NotificationServiceImpl
true, // this was the behaviour before introducing this parameter
bool checkForFinalDeliveryStatus =
true, // this was the behaviour before introducing this parameter
bool encryptValue = true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the comment // this was the behaviour before introducing this parameter

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Function(NotificationResult)? onSuccess,
Function(NotificationResult)? onError,
Function(NotificationResult)? onSentToSecondary}) async {
Expand All @@ -331,6 +332,7 @@ class NotificationServiceImpl
}

try {
notificationParams.atKey.metadata.isEncrypted = encryptValue;
// If sharedBy atSign is null, default to current atSign.
if (notificationParams.atKey.sharedBy.isNull) {
notificationParams.atKey.sharedBy = _atClient.getCurrentAtSign();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ class NotificationRequestTransformer
// prepares notification builder
NotifyVerbBuilder builder = await _prepareNotificationBuilder(
notificationParams, atClientPreference);
// If notification value is not null, encrypt the value
if (notificationParams.value.isNotNull) {
// If notification value is set and metadata.isEncrypted is true, encrypt
// the value.
if (notificationParams.value.isNotNull &&
notificationParams.atKey.metadata.isEncrypted) {
builder.value = await _encryptNotificationValue(
notificationParams.atKey, notificationParams.value!);
} else {
builder.value = notificationParams.value;
}
// add metadata to notify verb builder.
// Encrypt the data and then call addMetadataToBuilder method inorder to
Expand Down
2 changes: 1 addition & 1 deletion packages/at_client/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: The at_client library is the non-platform specific Client SDK which
##
##
## NB: When incrementing the version, please also increment the version in AtClientConfig file
version: 3.2.0
version: 3.2.1
## NB: When incrementing the version, please also increment the version in AtClientConfig file
##

Expand Down
98 changes: 94 additions & 4 deletions packages/at_client/test/notification_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class MockLocalSecondary extends Mock implements LocalSecondary {
SecondaryKeyStore? keyStore = MockSecondaryKeyStore();
}

class MockRemoteSecondary extends Mock implements RemoteSecondary {}

class MockAtClientImpl extends Mock implements AtClientImpl {
@override
String? getCurrentAtSign() {
Expand Down Expand Up @@ -103,8 +105,7 @@ void main() {
AtKeyEncryptionManager mockAtKeyEncryptionManager =
MockAtKeyEncryptionManager();
AtLookupImpl mockAtLookupImpl = MockAtLookupImpl();

group('A group of test to validate notification request processor', () {
group('A group of test to validate notification request transformer', () {
var value = '+91908909933';
late SharedKeyEncryption mockSharedKeyEncryptionImpl;
setUp(() {
Expand All @@ -131,7 +132,7 @@ void main() {
});

test(
'A test to validate notification request with value return verb builder',
'A test to validate notification request with unencrypted value return verb builder',
() async {
var notificationParams = NotificationParams.forUpdate(
(AtKey.shared('phone', namespace: 'wavi')..sharedWith('@bob'))
Expand All @@ -152,9 +153,37 @@ void main() {
expect(notifyVerbBuilder.messageType, MessageTypeEnum.key);
expect(notifyVerbBuilder.priority, PriorityEnum.high);
expect(notifyVerbBuilder.strategy, StrategyEnum.latest);
expect(notifyVerbBuilder.value, value);
expect(notifyVerbBuilder.notifier, 'test-notifier');
expect(notifyVerbBuilder.latestN, 2);
expect(notifyVerbBuilder.ttln, Duration(minutes: 1).inMilliseconds);
});

test(
'A test to validate notification request with encrypted value return verb builder',
() async {
var notificationParams = NotificationParams.forUpdate(
(AtKey.shared('phone', namespace: 'wavi')..sharedWith('@bob'))
.build(),
value: value,
priority: PriorityEnum.high,
strategy: StrategyEnum.latest,
notifier: 'test-notifier',
latestN: 2,
notificationExpiry: Duration(minutes: 1));
notificationParams.atKey.metadata.isEncrypted = true;
var notifyVerbBuilder = await NotificationRequestTransformer(
'@alice',
AtClientPreference()..namespace = 'wavi',
mockSharedKeyEncryptionImpl)
.transform(notificationParams);
expect(notifyVerbBuilder.atKey.key, 'phone.wavi');
expect(notifyVerbBuilder.atKey.sharedWith, '@bob');
expect(notifyVerbBuilder.messageType, MessageTypeEnum.key);
expect(notifyVerbBuilder.priority, PriorityEnum.high);
expect(notifyVerbBuilder.strategy, StrategyEnum.latest);
expect(notifyVerbBuilder.value, 'encryptedValue');
expect(notifyVerbBuilder.atKey.metadata.sharedKeyEnc, 'sharedKeyEnc');
expect(notifyVerbBuilder.atKey.metadata.pubKeyCS, 'publicKeyCS');
expect(notifyVerbBuilder.notifier, 'test-notifier');
expect(notifyVerbBuilder.latestN, 2);
expect(notifyVerbBuilder.ttln, Duration(minutes: 1).inMilliseconds);
Expand Down Expand Up @@ -221,6 +250,67 @@ void main() {
e is SecondaryConnectException &&
e.message == 'Unable to connect to secondary server')));
});

test(
'A test to validate encrypted value and shared encryption key is set in verb builder when isEncrypted is set to true in metadata',
() async {
var notificationParams = NotificationParams.forUpdate(
(AtKey.shared('phone', namespace: 'wavi')..sharedWith('@bob'))
.build(),
value: value,
priority: PriorityEnum.high,
strategy: StrategyEnum.latest,
notifier: 'test-notifier',
latestN: 2,
notificationExpiry: Duration(minutes: 1));
notificationParams.atKey.metadata.isEncrypted = true;
var notifyVerbBuilder = await NotificationRequestTransformer(
'@alice',
AtClientPreference()..namespace = 'wavi',
mockSharedKeyEncryptionImpl)
.transform(notificationParams);
expect(notifyVerbBuilder.value, 'encryptedValue');
expect(notifyVerbBuilder.atKey.metadata.sharedKeyEnc, 'sharedKeyEnc');
});
test(
'A test to validate unencrypted value is set in verb builder when isEncrypted is set to false in metadata',
() async {
var notificationParams = NotificationParams.forUpdate(
(AtKey.shared('phone', namespace: 'wavi')..sharedWith('@bob'))
.build(),
value: value,
priority: PriorityEnum.high,
strategy: StrategyEnum.latest,
notifier: 'test-notifier',
latestN: 2,
notificationExpiry: Duration(minutes: 1));
notificationParams.atKey.metadata.isEncrypted = false;
var notifyVerbBuilder = await NotificationRequestTransformer(
'@alice',
AtClientPreference()..namespace = 'wavi',
mockSharedKeyEncryptionImpl)
.transform(notificationParams);
expect(notifyVerbBuilder.value, value);
});
test(
'A test to validate unencrypted value is set in verb builder when isEncrypted is NOT set in metadata',
() async {
var notificationParams = NotificationParams.forUpdate(
(AtKey.shared('phone', namespace: 'wavi')..sharedWith('@bob'))
.build(),
value: value,
priority: PriorityEnum.high,
strategy: StrategyEnum.latest,
notifier: 'test-notifier',
latestN: 2,
notificationExpiry: Duration(minutes: 1));
var notifyVerbBuilder = await NotificationRequestTransformer(
'@alice',
AtClientPreference()..namespace = 'wavi',
mockSharedKeyEncryptionImpl)
.transform(notificationParams);
expect(notifyVerbBuilder.value, value);
});
});

group('A group of test to validate notification response transformer', () {
Expand Down
1 change: 1 addition & 0 deletions packages/at_client/test/test_utils/no_op_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class NoOpNotificationService implements NotificationService {
Future<NotificationResult> notify(NotificationParams notificationParams,
{bool waitForFinalDeliveryStatus = true,
bool checkForFinalDeliveryStatus = true,
bool encryptValue = true,
Function(NotificationResult p1)? onSuccess,
Function(NotificationResult p1)? onError,
Function(NotificationResult p1)? onSentToSecondary}) {
Expand Down
33 changes: 25 additions & 8 deletions tests/at_functional_test/test/atclient_notify_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,29 @@ void main() {
..sharedWith = sharedWithAtSign
..namespace = namespace;
var value = '+1 100 200 300';
await atClientManager.atClient.notificationService
var notificationResult = await atClientManager.atClient.notificationService
.notify(NotificationParams.forUpdate(phoneKey, value: value));
var notification = await atClientManager.atClient.notificationService
.fetch(notificationResult.notificationID);
print(notification.value);
// encrypted value should not be equal to actual value
expect(notification.value == value, false);
});

test('verify unencrypted value is returned when encryptValue is set to false',
() async {
var phoneKey = AtKey()
..key = 'phone'
..sharedWith = sharedWithAtSign
..namespace = namespace;
var value = '+1 100 200 300';
var notificationResult = await atClientManager.atClient.notificationService
.notify(NotificationParams.forUpdate(phoneKey, value: value),
encryptValue: false);
var notificationId = notificationResult.notificationID;
var notification = await atClientManager.atClient.notificationService
.fetch(notificationId);
expect(notification.value, value);
});

test('notify deletion of a key to sharedWith atSign', () async {
Expand Down Expand Up @@ -217,12 +238,10 @@ void main() {
}
});

group('A group of tests for notification fetch', () {
group('A group of tests for notification fetch', () {
test('A test to verify non existent notification', () async {
await AtClientManager.getInstance().setCurrentAtSign(
currentAtSign,
namespace,
TestUtils.getPreference(currentAtSign));
currentAtSign, namespace, TestUtils.getPreference(currentAtSign));
var notificationResult = await AtClientManager.getInstance()
.atClient
.notificationService
Expand All @@ -235,9 +254,7 @@ void main() {
for (int i = 0; i < 10; i++) {
print('Testing notification expiry - test run #$i');
await AtClientManager.getInstance().setCurrentAtSign(
currentAtSign,
namespace,
TestUtils.getPreference(currentAtSign));
currentAtSign, namespace, TestUtils.getPreference(currentAtSign));
var atKey = (AtKey.shared('test-notification-expiry',
namespace: 'wavi', sharedBy: currentAtSign)
..sharedWith(sharedWithAtSign))
Expand Down
Loading