Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9756f47
Update Gradle so project can be build in latest Android Studio
adriantuk Oct 16, 2025
30906b1
Implement message signing functionality and add tests for HTTP messag…
adriantuk Oct 16, 2025
a9d10f0
Build fix
adriantuk Oct 16, 2025
23aaae7
Add debug logging for message signing process. Currently message sign…
adriantuk Oct 17, 2025
0e7083f
Exclude 'content-length' header from signing when body is empty, as i…
adriantuk Oct 20, 2025
666c4ff
enhance DER signature validation, add defensive checks to ensure we n…
adriantuk Oct 22, 2025
22c0317
Implement Approov-TraceID support for SDK 3.5.2; Use full URL to fetc…
adriantuk Oct 23, 2025
8a84734
Implement HTTP Structured Fields Value syntax defined in IETF RFC 9651
adriantuk Oct 27, 2025
7b9e267
adding more tests with focus on sfv addition
adriantuk Oct 27, 2025
4972ffc
Refactor enableMessageSigning to include mutex protection and validat…
adriantuk Oct 27, 2025
9660898
add more edge cases tests for structured fields; make enableMessageSi…
adriantuk Oct 27, 2025
f99ee0a
Add comments to clarify validation logic and serialization rules in s…
adriantuk Nov 3, 2025
cc1ea7d
Enhance documentation with detailed comments for Structured Fields an…
adriantuk Nov 3, 2025
ec31621
Remove the fallback between algorithms; the user should explicitly sp…
adriantuk Nov 3, 2025
722a3fa
Message signing now derives the signer and header label directly from…
adriantuk Nov 4, 2025
67eb970
comment improvement
adriantuk Nov 4, 2025
4e03059
Implemented `getAccountMessageSignature` method in Dart and platform …
adriantuk Nov 4, 2025
151ee50
Add tests for getAccountMessageSignature method
adriantuk Nov 4, 2025
15f4581
Add structured field tests json parser implementation.
adriantuk Nov 10, 2025
91de879
Merge branch 'feature/msg_signing' into feature/traceID
adriantuk Nov 10, 2025
a5adf9f
Merge pull request #26 from approov/feature/traceID
adriantuk Nov 10, 2025
23b2e07
spacing and formatting fixes, allign `else if`
adriantuk Nov 12, 2025
c0786fc
Use SDK 3.5.2
adriantuk Nov 12, 2025
952800c
Merge branch 'main' into feature/msg_signing
adriantuk Nov 12, 2025
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@
.gradle
.dart_tool
pubspec.lock
.idea
android/local.properties
android/build/
AGENTS.md
build/
# Exclude .json test files used for testing only.
test/third_party/structured_field_tests/
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,15 @@
A wrapper for the iOS [Approov SDK](https://github.com/approov/approov-ios-sdk) and Android [Approov SDK](https://github.com/approov/approov-android-sdk) to enable easy integration when using [`Flutter`](https://flutter.dev) for making the API calls that you wish to protect with Approov. In order to use this you will need a trial or paid [Approov](https://www.approov.io) account.

See the [Quickstart](https://github.com/approov/quickstart-flutter-httpclient) for usage instructions.

## Structured Field Compliance Tests

The HTTP message signing implementation relies on Structured Field values, so we vendor the official [httpwg/structured-field-tests](https://github.com/httpwg/structured-field-tests) fixtures for full test coverage.

Clone the [httpwg/structured-field-tests](https://github.com/httpwg/structured-field-tests), copy the `.json`, `README.md`, `LICENSE.md`, and `serialisation-tests/` assets into `test/third_party/structured_field_tests`, and then run the following to execute the conformance suite:

```
flutter test test/structured_fields_conformance_test.dart
```

The harness focuses on serialization/canonicalization (parsing is not implemented in this package). All JSON fixtures (including `can_fail` advisories and the serialisation edge cases) are exercised; multi-value field inputs are normalised using the HTTP list concatenation rules so they can be compared against the single-value serializer APIs in this package.
15 changes: 7 additions & 8 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ version '1.0'
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:8.5.0'
}
}

rootProject.allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
Expand All @@ -25,18 +24,18 @@ apply plugin: 'com.android.library'
android {
namespace 'com.criticalblue.approov_service_flutter_httpclient'

compileSdkVersion 29
compileSdk 34

defaultConfig {
minSdkVersion 19
minSdk 21
}
lintOptions {
lint {
disable 'InvalidPackage'
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}

Expand Down
3 changes: 2 additions & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Thu Oct 16 13:35:42 BST 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,27 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
} catch(Exception e) {
result.error("Approov.getMessageSignature", e.getLocalizedMessage(), null);
}
} else if (call.method.equals("getAccountMessageSignature")) {
try {
String messageSignature = Approov.getAccountMessageSignature((String) call.argument("message"));
result.success(messageSignature);
} catch (NoSuchMethodError e) {
try {
String messageSignature = Approov.getMessageSignature((String) call.argument("message"));
result.success(messageSignature);
} catch(Exception inner) {
result.error("Approov.getAccountMessageSignature", inner.getLocalizedMessage(), null);
}
} catch(Exception e) {
result.error("Approov.getAccountMessageSignature", e.getLocalizedMessage(), null);
}
} else if (call.method.equals("getInstallMessageSignature")) {
try {
String messageSignature = Approov.getInstallMessageSignature((String) call.argument("message"));
result.success(messageSignature);
} catch(Exception e) {
result.error("Approov.getInstallMessageSignature", e.getLocalizedMessage(), null);
}
} else if (call.method.equals("setUserProperty")) {
try {
Approov.setUserProperty(call.argument("property"));
Expand Down
3 changes: 3 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
31 changes: 30 additions & 1 deletion ios/Classes/ApproovHttpClientPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,37 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
} else if ([@"setDevKey" isEqualToString:call.method]) {
[Approov setDevKey:call.arguments[@"devKey"]];
result(nil);
} else if ([@"getMessageSignature" isEqualToString:call.method]) {
} else if ([@"getMessageSignature" isEqualToString:call.method]) {
@try {
result([Approov getMessageSignature:call.arguments[@"message"]]);
}
@catch (NSException *exception) {
result([FlutterError errorWithCode:@"Approov.getMessageSignature"
message:exception.reason
details:nil]);
}
} else if ([@"getAccountMessageSignature" isEqualToString:call.method]) {
@try {
if ([Approov respondsToSelector:@selector(getAccountMessageSignature:)]) {
result([Approov getAccountMessageSignature:call.arguments[@"message"]]);
} else {
result([Approov getMessageSignature:call.arguments[@"message"]]);
}
}
@catch (NSException *exception) {
result([FlutterError errorWithCode:@"Approov.getAccountMessageSignature"
message:exception.reason
details:nil]);
}
} else if ([@"getInstallMessageSignature" isEqualToString:call.method]) {
@try {
result([Approov getInstallMessageSignature:call.arguments[@"message"]]);
}
@catch (NSException *exception) {
result([FlutterError errorWithCode:@"Approov.getInstallMessageSignature"
message:exception.reason
details:nil]);
}
} else if ([@"setUserProperty" isEqualToString:call.method]) {
[Approov setUserProperty:call.arguments[@"property"]];
result(nil);
Expand Down
Loading