mirror of
https://github.com/we-promise/sure.git
synced 2026-05-25 21:44:56 +00:00
* Add mobile custom proxy headers * Clear login placeholders on focus Email/password fields ship with example values pre-filled. Tapping the field now clears the placeholder so users don't have to delete it manually. Skips clearing if the user has already edited the value. * Push Configuration as a route from Sign in Opening Configuration from the Sign in screen now uses Navigator.push instead of toggling a state flag, so Android back returns to Sign in instead of quitting the app. Saving the URL auto-pops the route. * Address PR review on custom proxy headers - Test Connection no longer leaves global ApiConfig headers mutated; unsaved edits are restored in a finally block after the probe. - _loadSavedUrl / _loadCustomHeaders wrap storage reads in try/catch and always finish initialization with sensible defaults. - Sanitization is now a single CustomProxyHeader.sanitize() reused by ApiConfig.setCustomProxyHeaders and CustomProxyHeadersService. - Brief comment on redactedValue explaining the length-obscuring design. * Harden custom proxy header validation and load path - validateValue now rejects ASCII control characters (CR/LF/tab/etc.) to prevent header-injection via crafted values. - loadHeaders moves the secure-storage read inside the try block so platform exceptions are caught the same way JSON parse errors are.
79 lines
2.5 KiB
Dart
79 lines
2.5 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:sure_mobile/models/custom_proxy_header.dart';
|
|
import 'package:sure_mobile/services/api_config.dart';
|
|
|
|
void main() {
|
|
setUp(() async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
ApiConfig.clearApiKeyAuth();
|
|
ApiConfig.setBaseUrl(ApiConfig.defaultBaseUrl);
|
|
ApiConfig.setCustomProxyHeaders([]);
|
|
});
|
|
|
|
test('adds custom proxy headers to token auth headers', () {
|
|
ApiConfig.setCustomProxyHeaders([
|
|
CustomProxyHeader(name: 'X-Auth-Id', value: 'id'),
|
|
CustomProxyHeader(name: 'X-Auth-Secret', value: 'secret'),
|
|
]);
|
|
|
|
expect(ApiConfig.getAuthHeaders('token'), {
|
|
'X-Auth-Id': 'id',
|
|
'X-Auth-Secret': 'secret',
|
|
'Authorization': 'Bearer token',
|
|
'Accept': 'application/json',
|
|
});
|
|
});
|
|
|
|
test('adds custom proxy headers to unauthenticated json headers', () {
|
|
ApiConfig.setCustomProxyHeaders([
|
|
CustomProxyHeader(name: 'X-Mobile-Bypass', value: 'pass'),
|
|
]);
|
|
|
|
expect(ApiConfig.jsonHeaders(), {
|
|
'X-Mobile-Bypass': 'pass',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
});
|
|
});
|
|
|
|
test('drops headers with reserved names', () {
|
|
ApiConfig.setCustomProxyHeaders([
|
|
CustomProxyHeader(name: 'Accept', value: 'text/plain'),
|
|
CustomProxyHeader(name: 'Authorization', value: 'should-be-dropped'),
|
|
CustomProxyHeader(name: 'X-Api-Key', value: 'should-be-dropped-too'),
|
|
CustomProxyHeader(name: 'Content-Type', value: 'application/xml'),
|
|
CustomProxyHeader(name: 'X-Auth-Id', value: 'id'),
|
|
]);
|
|
|
|
final result = ApiConfig.customProxyHeaders;
|
|
expect(result.length, 1);
|
|
expect(result.first.name, 'X-Auth-Id');
|
|
});
|
|
|
|
test('deduplicates headers by normalized name keeping the last value', () {
|
|
ApiConfig.setCustomProxyHeaders([
|
|
CustomProxyHeader(name: 'X-Auth-Id', value: 'first'),
|
|
CustomProxyHeader(name: 'x-auth-id', value: 'second'),
|
|
CustomProxyHeader(name: 'X-Auth-Id', value: 'third'),
|
|
]);
|
|
|
|
final result = ApiConfig.customProxyHeaders;
|
|
expect(result.length, 1);
|
|
expect(result.first.name, 'X-Auth-Id');
|
|
expect(result.first.value, 'third');
|
|
});
|
|
|
|
test('app managed headers win over custom headers', () {
|
|
ApiConfig.setCustomProxyHeaders([
|
|
CustomProxyHeader(name: 'Accept', value: 'text/plain'),
|
|
CustomProxyHeader(name: 'X-Auth-Id', value: 'id'),
|
|
]);
|
|
|
|
expect(ApiConfig.htmlHeaders(), {
|
|
'X-Auth-Id': 'id',
|
|
'Accept': 'text/html',
|
|
});
|
|
});
|
|
}
|