Skip to content

Commit 25c288b

Browse files
a7medevHeshamMegid
authored andcommitted
feat: support network logs obfuscation (#380)
Jira ID: MOB-12523
1 parent 3a9c0bd commit 25c288b

File tree

7 files changed

+171
-3
lines changed

7 files changed

+171
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v11.14.0...dev)
44

5+
### Added
6+
7+
- Add network logs obfuscation support using the new `NetworkLogger.obfuscateLog` API ([#380](https://github.com/Instabug/Instabug-Flutter/pull/380)).
8+
59
### Changed
610

711
- Bump Instabug iOS SDK to v11.14.0 ([#383](https://github.com/Instabug/Instabug-Flutter/pull/383)). [See release notes](https://github.com/Instabug/Instabug-iOS/releases/tag/11.14.0).

ios/Classes/Modules/InstabugApi.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#import <CoreText/CoreText.h>
33
#import <Flutter/Flutter.h>
44
#import "Instabug.h"
5+
#import "IBGNetworkLogger+CP.h"
56
#import "InstabugApi.h"
67
#import "ArgsRegistry.h"
78

@@ -28,6 +29,10 @@ - (void)initToken:(NSString *)token invocationEvents:(NSArray<NSString *> *)invo
2829
[inv setArgument:&(platformID) atIndex:2];
2930
[inv invoke];
3031
}
32+
33+
// Disable automatic capturing of native iOS network logs to avoid duplicate
34+
// logs of the same request when using a native network client like cupertino_http
35+
[IBGNetworkLogger disableAutomaticCapturingOfNetworkLogs];
3136

3237
IBGInvocationEvent resolvedEvents = 0;
3338

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#import <Instabug/Instabug.h>
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
@interface IBGNetworkLogger (CP)
6+
7+
+ (void)disableAutomaticCapturingOfNetworkLogs;
8+
9+
@end
10+
11+
NS_ASSUME_NONNULL_END

lib/src/modules/network_logger.dart

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import 'dart:async';
44

5+
import 'package:flutter/foundation.dart';
56
import 'package:instabug_flutter/src/generated/instabug.api.g.dart';
67
import 'package:instabug_flutter/src/models/network_data.dart';
78
import 'package:instabug_flutter/src/modules/apm.dart';
8-
import 'package:meta/meta.dart';
9+
import 'package:instabug_flutter/src/utils/network_manager.dart';
910

1011
class NetworkLogger {
1112
static var _host = InstabugHostApi();
13+
static var _manager = NetworkManager();
1214

1315
/// @nodoc
1416
@visibleForTesting
@@ -17,8 +19,34 @@ class NetworkLogger {
1719
_host = host;
1820
}
1921

22+
/// @nodoc
23+
@visibleForTesting
24+
// ignore: use_setters_to_change_properties
25+
static void $setManager(NetworkManager manager) {
26+
_manager = manager;
27+
}
28+
29+
/// Registers a callback to selectively obfuscate network log data.
30+
///
31+
/// The [callback] function takes a [NetworkData] object as its argument and
32+
/// should return a modified [NetworkData] object with sensitive information
33+
/// obfuscated.
34+
///
35+
/// Example:
36+
///
37+
/// ```dart
38+
/// NetworkLogger.obfuscateLog((data) {
39+
/// // Modify 'data' as needed and return it.
40+
/// });
41+
/// ```
42+
static void obfuscateLog(ObfuscateLogCallback callback) {
43+
_manager.setObfuscateLogCallback(callback);
44+
}
45+
2046
Future<void> networkLog(NetworkData data) async {
21-
await _host.networkLog(data.toJson());
22-
await APM.networkLogAndroid(data);
47+
final obfuscated = await _manager.obfuscateLog(data);
48+
49+
await _host.networkLog(obfuscated.toJson());
50+
await APM.networkLogAndroid(obfuscated);
2351
}
2452
}

lib/src/utils/network_manager.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import 'dart:async';
2+
3+
import 'package:instabug_flutter/instabug_flutter.dart';
4+
5+
typedef ObfuscateLogCallback = FutureOr<NetworkData> Function(NetworkData data);
6+
7+
/// Mockable [NetworkManager] responsible for processing network logs
8+
/// before they are sent to the native SDKs.
9+
class NetworkManager {
10+
ObfuscateLogCallback? _obfuscateLogCallback;
11+
12+
// ignore: use_setters_to_change_properties
13+
void setObfuscateLogCallback(ObfuscateLogCallback callback) {
14+
_obfuscateLogCallback = callback;
15+
}
16+
17+
FutureOr<NetworkData> obfuscateLog(NetworkData data) {
18+
if (_obfuscateLogCallback == null) {
19+
return data;
20+
}
21+
22+
return _obfuscateLogCallback!(data);
23+
}
24+
}

test/network_logger_test.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import 'dart:async';
2+
13
import 'package:flutter/widgets.dart';
24
import 'package:flutter_test/flutter_test.dart';
35
import 'package:instabug_flutter/instabug_flutter.dart';
46
import 'package:instabug_flutter/src/generated/apm.api.g.dart';
57
import 'package:instabug_flutter/src/generated/instabug.api.g.dart';
68
import 'package:instabug_flutter/src/utils/ibg_build_info.dart';
9+
import 'package:instabug_flutter/src/utils/network_manager.dart';
710
import 'package:mockito/annotations.dart';
811
import 'package:mockito/mockito.dart';
912

@@ -13,6 +16,7 @@ import 'network_logger_test.mocks.dart';
1316
ApmHostApi,
1417
InstabugHostApi,
1518
IBGBuildInfo,
19+
NetworkManager,
1620
])
1721
void main() {
1822
TestWidgetsFlutterBinding.ensureInitialized();
@@ -21,6 +25,7 @@ void main() {
2125
final mApmHost = MockApmHostApi();
2226
final mInstabugHost = MockInstabugHostApi();
2327
final mBuildInfo = MockIBGBuildInfo();
28+
final mManager = MockNetworkManager();
2429

2530
final logger = NetworkLogger();
2631
final data = NetworkData(
@@ -32,11 +37,20 @@ void main() {
3237
setUpAll(() {
3338
APM.$setHostApi(mApmHost);
3439
NetworkLogger.$setHostApi(mInstabugHost);
40+
NetworkLogger.$setManager(mManager);
3541
IBGBuildInfo.setInstance(mBuildInfo);
3642
});
3743

44+
setUp(() {
45+
reset(mApmHost);
46+
reset(mInstabugHost);
47+
reset(mBuildInfo);
48+
reset(mManager);
49+
});
50+
3851
test('[networkLog] should call 1 host method on iOS', () async {
3952
when(mBuildInfo.isAndroid).thenReturn(false);
53+
when(mManager.obfuscateLog(data)).thenReturn(data);
4054

4155
await logger.networkLog(data);
4256

@@ -51,6 +65,7 @@ void main() {
5165

5266
test('[networkLog] should call 2 host methods on Android', () async {
5367
when(mBuildInfo.isAndroid).thenReturn(true);
68+
when(mManager.obfuscateLog(data)).thenReturn(data);
5469

5570
await logger.networkLog(data);
5671

@@ -62,4 +77,35 @@ void main() {
6277
mApmHost.networkLogAndroid(data.toJson()),
6378
).called(1);
6479
});
80+
81+
test('[networkLog] should obfuscate network data before logging', () async {
82+
final obfuscated = data.copyWith(requestBody: 'obfuscated');
83+
84+
when(mBuildInfo.isAndroid).thenReturn(true);
85+
when(mManager.obfuscateLog(data)).thenReturn(obfuscated);
86+
87+
await logger.networkLog(data);
88+
89+
verify(
90+
mManager.obfuscateLog(data),
91+
).called(1);
92+
93+
verify(
94+
mInstabugHost.networkLog(obfuscated.toJson()),
95+
).called(1);
96+
97+
verify(
98+
mApmHost.networkLogAndroid(obfuscated.toJson()),
99+
).called(1);
100+
});
101+
102+
test('[obfuscateLog] should set obfuscation callback on manager', () async {
103+
FutureOr<NetworkData> callback(NetworkData data) => data;
104+
105+
NetworkLogger.obfuscateLog(callback);
106+
107+
verify(
108+
mManager.setObfuscateLogCallback(callback),
109+
).called(1);
110+
});
65111
}

test/network_manager_test.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import 'dart:async';
2+
3+
import 'package:flutter/widgets.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:instabug_flutter/instabug_flutter.dart';
6+
import 'package:instabug_flutter/src/utils/network_manager.dart';
7+
8+
void main() {
9+
TestWidgetsFlutterBinding.ensureInitialized();
10+
WidgetsFlutterBinding.ensureInitialized();
11+
12+
final data = NetworkData(
13+
url: "https://httpbin.org/get",
14+
method: "GET",
15+
startTime: DateTime.now(),
16+
);
17+
late NetworkManager manager;
18+
19+
setUp(() {
20+
manager = NetworkManager();
21+
});
22+
23+
test('[obfuscateLog] should return same data when obfuscate log callback',
24+
() async {
25+
final result = await manager.obfuscateLog(data);
26+
27+
expect(result, equals(data));
28+
});
29+
30+
test(
31+
'[obfuscateLog] should obfuscate data when [setObfuscateLogCallback] has set a callback',
32+
() async {
33+
final obfuscated = data.copyWith(requestBody: 'obfuscated');
34+
final completer = Completer<NetworkData>();
35+
FutureOr<NetworkData> callback(NetworkData data) {
36+
completer.complete(data);
37+
return obfuscated;
38+
}
39+
40+
manager.setObfuscateLogCallback(callback);
41+
42+
final result = await manager.obfuscateLog(data);
43+
44+
expect(completer.isCompleted, isTrue);
45+
46+
expect(await completer.future, data);
47+
48+
expect(result, equals(obfuscated));
49+
});
50+
}

0 commit comments

Comments
 (0)