mirror of
https://github.com/we-promise/sure.git
synced 2026-05-24 21:14: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.
48 lines
1.9 KiB
Dart
48 lines
1.9 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:sure_mobile/models/custom_proxy_header.dart';
|
|
|
|
void main() {
|
|
group('CustomProxyHeader', () {
|
|
test('serializes trimmed header name and value', () {
|
|
final header = CustomProxyHeader(name: ' X-Auth-Id ', value: ' abc ');
|
|
|
|
expect(header.name, 'X-Auth-Id');
|
|
expect(header.value, 'abc');
|
|
expect(header.toJson(), {
|
|
'name': 'X-Auth-Id',
|
|
'value': 'abc',
|
|
});
|
|
expect(CustomProxyHeader.fromJson(header.toJson()), header);
|
|
});
|
|
|
|
test('rejects empty, malformed, and reserved names', () {
|
|
expect(CustomProxyHeader.validateName(''), isNotNull);
|
|
expect(CustomProxyHeader.validateName('Bad Header'), isNotNull);
|
|
expect(CustomProxyHeader.validateName('Bad:Header'), isNotNull);
|
|
expect(CustomProxyHeader.validateName('Authorization'), isNotNull);
|
|
expect(CustomProxyHeader.validateName('X-Api-Key'), isNotNull);
|
|
expect(CustomProxyHeader.validateName('Accept'), isNotNull);
|
|
expect(CustomProxyHeader.validateName('Content-Type'), isNotNull);
|
|
});
|
|
|
|
test('allows custom header names with hyphens', () {
|
|
expect(CustomProxyHeader.validateName('X-Auth-Id'), isNull);
|
|
expect(CustomProxyHeader.validateName('X-Auth-Secret'), isNull);
|
|
});
|
|
|
|
test('rejects values containing control characters (header injection)', () {
|
|
expect(CustomProxyHeader.validateValue('abc\r\nInjected: 1'), isNotNull);
|
|
expect(CustomProxyHeader.validateValue('abc\tdef'), isNotNull);
|
|
expect(CustomProxyHeader.validateValue('abc\x7Fdef'), isNotNull);
|
|
expect(CustomProxyHeader.validateValue('plain value with spaces'), isNull);
|
|
});
|
|
|
|
test('redacts values for display', () {
|
|
expect(
|
|
CustomProxyHeader(name: 'X-Auth-Secret', value: '1234567890').redactedValue,
|
|
'••••••7890',
|
|
);
|
|
});
|
|
});
|
|
}
|