mirror of
https://github.com/foss42/apidash.git
synced 2025-12-02 18:57:05 +08:00
Fix critical vulnerabilities: Remove sensitive logging, add JS validation, add security dependencies
Co-authored-by: animator <615622+animator@users.noreply.github.com>
This commit is contained in:
@@ -44,6 +44,36 @@ class JsRuntimeNotifier extends StateNotifier<JsRuntimeState> {
|
|||||||
late final JavascriptRuntime _runtime;
|
late final JavascriptRuntime _runtime;
|
||||||
String? _currentRequestId;
|
String? _currentRequestId;
|
||||||
|
|
||||||
|
// Security: Maximum script length to prevent DoS attacks
|
||||||
|
static const int _maxScriptLength = 50000; // 50KB
|
||||||
|
|
||||||
|
// Security: Dangerous JavaScript patterns that could lead to code injection
|
||||||
|
static const List<String> _dangerousPatterns = [
|
||||||
|
r'eval\s*\(',
|
||||||
|
r'Function\s*\(',
|
||||||
|
r'constructor\s*\[',
|
||||||
|
r'__proto__',
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Validates user script for basic security checks
|
||||||
|
/// Returns null if valid, error message if invalid
|
||||||
|
String? _validateScript(String script) {
|
||||||
|
// Check script length to prevent DoS
|
||||||
|
if (script.length > _maxScriptLength) {
|
||||||
|
return 'Script exceeds maximum length of $_maxScriptLength characters';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for dangerous patterns
|
||||||
|
for (final pattern in _dangerousPatterns) {
|
||||||
|
final regex = RegExp(pattern, caseSensitive: false);
|
||||||
|
if (regex.hasMatch(script)) {
|
||||||
|
return 'Script contains potentially dangerous pattern: ${pattern.replaceAll(r'\s*\(', '(').replaceAll(r'\s*\[', '[')}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // Script is valid
|
||||||
|
}
|
||||||
|
|
||||||
void _initialize() {
|
void _initialize() {
|
||||||
if (state.initialized) return;
|
if (state.initialized) return;
|
||||||
_runtime = getJavascriptRuntime();
|
_runtime = getJavascriptRuntime();
|
||||||
@@ -100,7 +130,26 @@ class JsRuntimeNotifier extends StateNotifier<JsRuntimeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final httpRequest = currentRequestModel.httpRequestModel;
|
final httpRequest = currentRequestModel.httpRequestModel;
|
||||||
final userScript = currentRequestModel.preRequestScript;
|
final userScript = currentRequestModel.preRequestScript!;
|
||||||
|
|
||||||
|
// Security: Validate user script before execution
|
||||||
|
final validationError = _validateScript(userScript);
|
||||||
|
if (validationError != null) {
|
||||||
|
final term = ref.read(terminalStateProvider.notifier);
|
||||||
|
term.logJs(
|
||||||
|
level: 'error',
|
||||||
|
args: ['Script validation failed', validationError],
|
||||||
|
context: 'preRequest',
|
||||||
|
contextRequestId: requestId,
|
||||||
|
);
|
||||||
|
state = state.copyWith(lastError: validationError);
|
||||||
|
// Return original request without executing the script
|
||||||
|
return (
|
||||||
|
updatedRequest: httpRequest!,
|
||||||
|
updatedEnvironment: activeEnvironment,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final requestJson = jsonEncode(httpRequest?.toJson());
|
final requestJson = jsonEncode(httpRequest?.toJson());
|
||||||
final environmentJson = jsonEncode(activeEnvironment);
|
final environmentJson = jsonEncode(activeEnvironment);
|
||||||
final dataInjection = '''
|
final dataInjection = '''
|
||||||
@@ -190,7 +239,26 @@ class JsRuntimeNotifier extends StateNotifier<JsRuntimeState> {
|
|||||||
|
|
||||||
final httpRequest = currentRequestModel.httpRequestModel; // for future use
|
final httpRequest = currentRequestModel.httpRequestModel; // for future use
|
||||||
final httpResponse = currentRequestModel.httpResponseModel;
|
final httpResponse = currentRequestModel.httpResponseModel;
|
||||||
final userScript = currentRequestModel.postRequestScript;
|
final userScript = currentRequestModel.postRequestScript!;
|
||||||
|
|
||||||
|
// Security: Validate user script before execution
|
||||||
|
final validationError = _validateScript(userScript);
|
||||||
|
if (validationError != null) {
|
||||||
|
final term = ref.read(terminalStateProvider.notifier);
|
||||||
|
term.logJs(
|
||||||
|
level: 'error',
|
||||||
|
args: ['Script validation failed', validationError],
|
||||||
|
context: 'postResponse',
|
||||||
|
contextRequestId: requestId,
|
||||||
|
);
|
||||||
|
state = state.copyWith(lastError: validationError);
|
||||||
|
// Return original response without executing the script
|
||||||
|
return (
|
||||||
|
updatedResponse: httpResponse!,
|
||||||
|
updatedEnvironment: activeEnvironment,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final requestJson = jsonEncode(httpRequest?.toJson());
|
final requestJson = jsonEncode(httpRequest?.toJson());
|
||||||
final responseJson = jsonEncode(httpResponse?.toJson());
|
final responseJson = jsonEncode(httpResponse?.toJson());
|
||||||
final environmentJson = jsonEncode(activeEnvironment);
|
final environmentJson = jsonEncode(activeEnvironment);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ Future<bool> openHiveBoxes() async {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("ERROR OPEN HIVE BOXES: $e");
|
// Error opening Hive boxes - logging suppressed for security
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ Future<void> clearHiveBoxes() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("ERROR CLEAR HIVE BOXES: $e");
|
// Error clearing Hive boxes - logging suppressed for security
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ Future<void> deleteHiveBoxes() async {
|
|||||||
}
|
}
|
||||||
await Hive.close();
|
await Hive.close();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("ERROR DELETE HIVE BOXES: $e");
|
// Error deleting Hive boxes - logging suppressed for security
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ class HiveHandler {
|
|||||||
late final LazyBox dashBotBox;
|
late final LazyBox dashBotBox;
|
||||||
|
|
||||||
HiveHandler() {
|
HiveHandler() {
|
||||||
debugPrint("Trying to open Hive boxes");
|
// Initialize Hive boxes
|
||||||
dataBox = Hive.box(kDataBox);
|
dataBox = Hive.box(kDataBox);
|
||||||
environmentBox = Hive.box(kEnvironmentBox);
|
environmentBox = Hive.box(kEnvironmentBox);
|
||||||
historyMetaBox = Hive.box(kHistoryMetaBox);
|
historyMetaBox = Hive.box(kHistoryMetaBox);
|
||||||
|
|||||||
@@ -221,8 +221,6 @@ Future<HttpRequestModel> handleAuth(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint(res.$1.credentials.accessToken);
|
|
||||||
|
|
||||||
// Add the access token to the request headers
|
// Add the access token to the request headers
|
||||||
updatedHeaders.add(
|
updatedHeaders.add(
|
||||||
NameValueModel(
|
NameValueModel(
|
||||||
@@ -238,7 +236,6 @@ Future<HttpRequestModel> handleAuth(
|
|||||||
oauth2Model: oauth2,
|
oauth2Model: oauth2,
|
||||||
credentialsFile: credentialsFile,
|
credentialsFile: credentialsFile,
|
||||||
);
|
);
|
||||||
debugPrint(client.credentials.accessToken);
|
|
||||||
|
|
||||||
// Add the access token to the request headers
|
// Add the access token to the request headers
|
||||||
updatedHeaders.add(
|
updatedHeaders.add(
|
||||||
@@ -250,12 +247,10 @@ Future<HttpRequestModel> handleAuth(
|
|||||||
updatedHeaderEnabledList.add(true);
|
updatedHeaderEnabledList.add(true);
|
||||||
break;
|
break;
|
||||||
case OAuth2GrantType.resourceOwnerPassword:
|
case OAuth2GrantType.resourceOwnerPassword:
|
||||||
debugPrint("==Resource Owner Password==");
|
|
||||||
final client = await oAuth2ResourceOwnerPasswordGrantHandler(
|
final client = await oAuth2ResourceOwnerPasswordGrantHandler(
|
||||||
oauth2Model: oauth2,
|
oauth2Model: oauth2,
|
||||||
credentialsFile: credentialsFile,
|
credentialsFile: credentialsFile,
|
||||||
);
|
);
|
||||||
debugPrint(client.credentials.accessToken);
|
|
||||||
|
|
||||||
// Add the access token to the request headers
|
// Add the access token to the request headers
|
||||||
updatedHeaders.add(
|
updatedHeaders.add(
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ dependencies:
|
|||||||
flutter_markdown: ^0.7.6+2
|
flutter_markdown: ^0.7.6+2
|
||||||
flutter_portal: ^1.1.4
|
flutter_portal: ^1.1.4
|
||||||
flutter_riverpod: ^2.5.1
|
flutter_riverpod: ^2.5.1
|
||||||
|
flutter_secure_storage: ^9.0.0
|
||||||
flutter_svg: ^2.0.17
|
flutter_svg: ^2.0.17
|
||||||
fvp: ^0.32.1
|
fvp: ^0.32.1
|
||||||
highlight: ^0.7.0
|
highlight: ^0.7.0
|
||||||
@@ -47,6 +48,7 @@ dependencies:
|
|||||||
just_audio: ^0.9.46
|
just_audio: ^0.9.46
|
||||||
just_audio_mpv: ^0.1.7
|
just_audio_mpv: ^0.1.7
|
||||||
just_audio_windows: ^0.2.0
|
just_audio_windows: ^0.2.0
|
||||||
|
logging: ^1.2.0
|
||||||
lottie: ^3.3.1
|
lottie: ^3.3.1
|
||||||
markdown: ^7.3.0
|
markdown: ^7.3.0
|
||||||
mime_dart: ^3.0.0
|
mime_dart: ^3.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user