@sun-asterisk/sunlint 1.3.43 → 1.3.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/dart_analyzer/README.md +226 -0
  2. package/dart_analyzer/analysis_options.yaml +66 -0
  3. package/dart_analyzer/bin/sunlint-dart-macos +0 -0
  4. package/dart_analyzer/bin/sunlint_dart_analyzer.dart +124 -0
  5. package/dart_analyzer/lib/analyzer_service.dart +625 -0
  6. package/dart_analyzer/lib/json_rpc_server.dart +275 -0
  7. package/dart_analyzer/lib/models/rule.dart +67 -0
  8. package/dart_analyzer/lib/models/symbol_table.dart +607 -0
  9. package/dart_analyzer/lib/models/violation.dart +69 -0
  10. package/dart_analyzer/lib/rules/base_analyzer.dart +52 -0
  11. package/dart_analyzer/lib/rules/common/C002_no_duplicate_code.dart +344 -0
  12. package/dart_analyzer/lib/rules/common/C003_no_vague_abbreviations.dart +318 -0
  13. package/dart_analyzer/lib/rules/common/C006_function_naming.dart +219 -0
  14. package/dart_analyzer/lib/rules/common/C008_variable_declaration_locality.dart +205 -0
  15. package/dart_analyzer/lib/rules/common/C010_limit_block_nesting.dart +162 -0
  16. package/dart_analyzer/lib/rules/common/C012_command_query_separation.dart +214 -0
  17. package/dart_analyzer/lib/rules/common/C013_no_dead_code.dart +225 -0
  18. package/dart_analyzer/lib/rules/common/C014_dependency_injection.dart +249 -0
  19. package/dart_analyzer/lib/rules/common/C017_constructor_logic.dart +158 -0
  20. package/dart_analyzer/lib/rules/common/C018_no_throw_generic_error.dart +141 -0
  21. package/dart_analyzer/lib/rules/common/C019_log_level_usage.dart +165 -0
  22. package/dart_analyzer/lib/rules/common/C020_unused_imports.dart +128 -0
  23. package/dart_analyzer/lib/rules/common/C021_import_organization.dart +86 -0
  24. package/dart_analyzer/lib/rules/common/C023_no_duplicate_variable.dart +112 -0
  25. package/dart_analyzer/lib/rules/common/C024_no_scatter_hardcoded_constants.dart +79 -0
  26. package/dart_analyzer/lib/rules/common/C029_catch_block_logging.dart +81 -0
  27. package/dart_analyzer/lib/rules/common/C030_use_custom_error_classes.dart +77 -0
  28. package/dart_analyzer/lib/rules/common/C031_validation_separation.dart +90 -0
  29. package/dart_analyzer/lib/rules/common/C033_separate_service_repository.dart +80 -0
  30. package/dart_analyzer/lib/rules/common/C035_error_logging_context.dart +148 -0
  31. package/dart_analyzer/lib/rules/common/C040_centralized_validation.dart +84 -0
  32. package/dart_analyzer/lib/rules/common/C041_no_sensitive_hardcode.dart +103 -0
  33. package/dart_analyzer/lib/rules/common/C042_boolean_name_prefix.dart +105 -0
  34. package/dart_analyzer/lib/rules/common/C043_no_console_or_print.dart +101 -0
  35. package/dart_analyzer/lib/rules/common/C047_no_duplicate_retry_logic.dart +94 -0
  36. package/dart_analyzer/lib/rules/common/C048_no_bypass_architectural_layers.dart +132 -0
  37. package/dart_analyzer/lib/rules/common/C052_parsing_or_data_transformation.dart +95 -0
  38. package/dart_analyzer/lib/rules/common/C060_no_override_superclass.dart +81 -0
  39. package/dart_analyzer/lib/rules/common/C065_one_behavior_per_test.dart +83 -0
  40. package/dart_analyzer/lib/rules/common/C067_no_hardcoded_config.dart +89 -0
  41. package/dart_analyzer/lib/rules/common/C070_no_real_time_tests.dart +99 -0
  42. package/dart_analyzer/lib/rules/common/C072_single_test_behavior.dart +78 -0
  43. package/dart_analyzer/lib/rules/common/C073_validate_required_config_on_startup.dart +82 -0
  44. package/dart_analyzer/lib/rules/common/C075_explicit_return_types.dart +85 -0
  45. package/dart_analyzer/lib/rules/common/C076_explicit_function_types.dart +104 -0
  46. package/dart_analyzer/lib/rules/dart/D001_recommended_lint_rules.dart +309 -0
  47. package/dart_analyzer/lib/rules/dart/D002_dispose_resources.dart +338 -0
  48. package/dart_analyzer/lib/rules/dart/D003_prefer_widgets_over_methods.dart +273 -0
  49. package/dart_analyzer/lib/rules/dart/D004_avoid_shrinkwrap_listview.dart +154 -0
  50. package/dart_analyzer/lib/rules/dart/D005_limit_widget_nesting.dart +265 -0
  51. package/dart_analyzer/lib/rules/dart/D006_prefer_extracting_large_callbacks.dart +135 -0
  52. package/dart_analyzer/lib/rules/dart/D007_prefer_init_first_dispose_last.dart +150 -0
  53. package/dart_analyzer/lib/rules/dart/D008_avoid_long_functions.dart +394 -0
  54. package/dart_analyzer/lib/rules/dart/D009_limit_function_parameters.dart +179 -0
  55. package/dart_analyzer/lib/rules/dart/D010_limit_cyclomatic_complexity.dart +257 -0
  56. package/dart_analyzer/lib/rules/dart/D011_prefer_named_parameters.dart +152 -0
  57. package/dart_analyzer/lib/rules/dart/D012_prefer_named_boolean_parameters.dart +156 -0
  58. package/dart_analyzer/lib/rules/dart/D013_single_public_class.dart +246 -0
  59. package/dart_analyzer/lib/rules/dart/D014_unsafe_collection_access.dart +202 -0
  60. package/dart_analyzer/lib/rules/dart/D015_copywith_all_parameters.dart +125 -0
  61. package/dart_analyzer/lib/rules/dart/D016_project_should_have_tests.dart +134 -0
  62. package/dart_analyzer/lib/rules/dart/D017_pubspec_dependencies_review.dart +187 -0
  63. package/dart_analyzer/lib/rules/dart/D018_remove_commented_code.dart +196 -0
  64. package/dart_analyzer/lib/rules/dart/D019_avoid_single_child_multi_child_widget.dart +161 -0
  65. package/dart_analyzer/lib/rules/dart/D020_limit_if_else_branches.dart +125 -0
  66. package/dart_analyzer/lib/rules/dart/D021_avoid_negated_boolean_checks.dart +227 -0
  67. package/dart_analyzer/lib/rules/dart/D022_use_setstate_correctly.dart +269 -0
  68. package/dart_analyzer/lib/rules/dart/D023_avoid_unnecessary_method_overrides.dart +191 -0
  69. package/dart_analyzer/lib/rules/dart/D024_avoid_unnecessary_stateful_widget.dart +194 -0
  70. package/dart_analyzer/lib/rules/dart/D025_avoid_nested_conditional_expressions.dart +90 -0
  71. package/dart_analyzer/lib/rules/security/S001_backend_auth_communications.dart +155 -0
  72. package/dart_analyzer/lib/rules/security/S002_os_command_injection.dart +159 -0
  73. package/dart_analyzer/lib/rules/security/S003_open_redirect_protection.dart +208 -0
  74. package/dart_analyzer/lib/rules/security/S004_sensitive_data_logging.dart +391 -0
  75. package/dart_analyzer/lib/rules/security/S005_trusted_service_authorization.dart +182 -0
  76. package/dart_analyzer/lib/rules/security/S006_no_default_credentials.dart +208 -0
  77. package/dart_analyzer/lib/rules/security/S007_output_encoding.dart +224 -0
  78. package/dart_analyzer/lib/rules/security/S008_svg_content_sanitization.dart +211 -0
  79. package/dart_analyzer/lib/rules/security/S009_no_insecure_encryption.dart +160 -0
  80. package/dart_analyzer/lib/rules/security/S010_use_csprng.dart +184 -0
  81. package/dart_analyzer/lib/rules/security/S011_ech_tls_config.dart +175 -0
  82. package/dart_analyzer/lib/rules/security/S012_hardcoded_secrets.dart +255 -0
  83. package/dart_analyzer/lib/rules/security/S013_tls_enforcement.dart +148 -0
  84. package/dart_analyzer/lib/rules/security/S014_tls_version_enforcement.dart +117 -0
  85. package/dart_analyzer/lib/rules/security/S015_insecure_tls_certificate.dart +315 -0
  86. package/dart_analyzer/lib/rules/security/S016_no_sensitive_querystring.dart +244 -0
  87. package/dart_analyzer/lib/rules/security/S017_use_parameterized_queries.dart +191 -0
  88. package/dart_analyzer/lib/rules/security/S018_no_sensitive_browser_storage.dart +175 -0
  89. package/dart_analyzer/lib/rules/security/S019_smtp_injection_protection.dart +166 -0
  90. package/dart_analyzer/lib/rules/security/S020_no_eval_dynamic_code.dart +149 -0
  91. package/dart_analyzer/lib/rules/security/S021_referrer_policy.dart +146 -0
  92. package/dart_analyzer/lib/rules/security/S022_escape_output_context.dart +111 -0
  93. package/dart_analyzer/lib/rules/security/S023_no_json_injection.dart +550 -0
  94. package/dart_analyzer/lib/rules/security/S024_xpath_xxe_protection.dart +299 -0
  95. package/dart_analyzer/lib/rules/security/S025_server_side_validation.dart +140 -0
  96. package/dart_analyzer/lib/rules/security/S026_tls_all_connections.dart +196 -0
  97. package/dart_analyzer/lib/rules/security/S027_mtls_certificate_validation.dart +195 -0
  98. package/dart_analyzer/lib/rules/security/S028_file_upload_size_limits.dart +186 -0
  99. package/dart_analyzer/lib/rules/security/S029_csrf_protection.dart +171 -0
  100. package/dart_analyzer/lib/rules/security/S030_directory_browsing_protection.dart +144 -0
  101. package/dart_analyzer/lib/rules/security/S031_secure_session_cookies.dart +118 -0
  102. package/dart_analyzer/lib/rules/security/S032_httponly_session_cookies.dart +114 -0
  103. package/dart_analyzer/lib/rules/security/S033_samesite_session_cookies.dart +120 -0
  104. package/dart_analyzer/lib/rules/security/S034_host_prefix_session_cookies.dart +160 -0
  105. package/dart_analyzer/lib/rules/security/S035_separate_app_hostnames.dart +117 -0
  106. package/dart_analyzer/lib/rules/security/S036_lfi_rfi_protection.dart +188 -0
  107. package/dart_analyzer/lib/rules/security/S037_cache_headers.dart +113 -0
  108. package/dart_analyzer/lib/rules/security/S038_no_version_headers.dart +114 -0
  109. package/dart_analyzer/lib/rules/security/S039_tls_certificate_validation.dart +131 -0
  110. package/dart_analyzer/lib/rules/security/S040_session_fixation_protection.dart +155 -0
  111. package/dart_analyzer/lib/rules/security/S041_session_token_invalidation.dart +201 -0
  112. package/dart_analyzer/lib/rules/security/S042_require_re_authentication_for_long_lived.dart +158 -0
  113. package/dart_analyzer/lib/rules/security/S043_password_changes_invalidate_all_sessions.dart +88 -0
  114. package/dart_analyzer/lib/rules/security/S044_re_authentication_required.dart +119 -0
  115. package/dart_analyzer/lib/rules/security/S045_brute_force_protection.dart +253 -0
  116. package/dart_analyzer/lib/rules/security/S046_jwt_algorithm_allowlist.dart +113 -0
  117. package/dart_analyzer/lib/rules/security/S047_oauth_pkce_protection.dart +124 -0
  118. package/dart_analyzer/lib/rules/security/S048_oauth_redirect_uri_validation.dart +134 -0
  119. package/dart_analyzer/lib/rules/security/S049_short_validity_tokens.dart +145 -0
  120. package/dart_analyzer/lib/rules/security/S050_reference_tokens_entropy.dart +234 -0
  121. package/dart_analyzer/lib/rules/security/S051_password_length_policy.dart +171 -0
  122. package/dart_analyzer/lib/rules/security/S052_weak_otp_entropy.dart +107 -0
  123. package/dart_analyzer/lib/rules/security/S053_generic_error_messages.dart +159 -0
  124. package/dart_analyzer/lib/rules/security/S054_no_default_accounts.dart +141 -0
  125. package/dart_analyzer/lib/rules/security/S055_content_type_validation.dart +324 -0
  126. package/dart_analyzer/lib/rules/security/S056_log_injection_protection.dart +119 -0
  127. package/dart_analyzer/lib/rules/security/S057_utc_logging.dart +114 -0
  128. package/dart_analyzer/lib/rules/security/S058_no_ssrf.dart +175 -0
  129. package/dart_analyzer/lib/rules/security/S059_disable_debug_mode.dart +172 -0
  130. package/dart_analyzer/lib/rules/security/S060_password_minimum_length.dart +170 -0
  131. package/dart_analyzer/lib/symbol_table_extractor.dart +510 -0
  132. package/dart_analyzer/lib/utils/common_utils.dart +26 -0
  133. package/dart_analyzer/pubspec.lock +557 -0
  134. package/dart_analyzer/pubspec.yaml +39 -0
  135. package/dart_analyzer/test/fixtures/complex_code.dart +95 -0
  136. package/docs/GENERATED_FILE_HANDLING_SUMMARY.md +2 -2
  137. package/package.json +3 -2
@@ -0,0 +1,146 @@
1
+ import 'package:analyzer/dart/ast/ast.dart';
2
+ import 'package:analyzer/dart/ast/visitor.dart';
3
+ import 'package:analyzer/source/line_info.dart';
4
+
5
+ import '../../models/rule.dart';
6
+ import '../../models/violation.dart';
7
+ import '../base_analyzer.dart';
8
+
9
+ /// S021: Set Referrer-Policy to prevent sensitive data leakage
10
+ /// Detect missing or weak Referrer-Policy headers
11
+ class S021ReferrerPolicyAnalyzer extends BaseAnalyzer {
12
+ @override
13
+ String get ruleId => 'S021';
14
+
15
+ // HTTP response/header patterns
16
+ static const _headerPatterns = [
17
+ 'setheader',
18
+ 'addheader',
19
+ 'headers',
20
+ 'response.',
21
+ 'httpresponse',
22
+ ];
23
+
24
+ // Weak referrer policies
25
+ static const _weakPolicies = [
26
+ 'unsafe-url',
27
+ 'no-referrer-when-downgrade',
28
+ ];
29
+
30
+ // Recommended policies
31
+ static const _recommendedPolicies = [
32
+ 'strict-origin-when-cross-origin',
33
+ 'same-origin',
34
+ 'no-referrer',
35
+ 'strict-origin',
36
+ ];
37
+
38
+ @override
39
+ List<Violation> analyze({
40
+ required CompilationUnit unit,
41
+ required String filePath,
42
+ required Rule rule,
43
+ required LineInfo lineInfo,
44
+ }) {
45
+ final violations = <Violation>[];
46
+ final visitor = _S021Visitor(
47
+ filePath: filePath,
48
+ lineInfo: lineInfo,
49
+ violations: violations,
50
+ analyzer: this,
51
+ );
52
+ unit.accept(visitor);
53
+ return violations;
54
+ }
55
+ }
56
+
57
+ class _S021Visitor extends RecursiveAstVisitor<void> {
58
+ final String filePath;
59
+ final LineInfo lineInfo;
60
+ final List<Violation> violations;
61
+ final S021ReferrerPolicyAnalyzer analyzer;
62
+
63
+ _S021Visitor({
64
+ required this.filePath,
65
+ required this.lineInfo,
66
+ required this.violations,
67
+ required this.analyzer,
68
+ });
69
+
70
+ @override
71
+ void visitMethodInvocation(MethodInvocation node) {
72
+ final source = node.toSource().toLowerCase();
73
+ final methodName = node.methodName.name.toLowerCase();
74
+
75
+ // Check for header setting operations
76
+ bool isHeaderOp = S021ReferrerPolicyAnalyzer._headerPatterns
77
+ .any((p) => source.contains(p) || methodName.contains(p));
78
+
79
+ if (isHeaderOp && source.contains('referrer')) {
80
+ // Check for weak policies
81
+ bool hasWeakPolicy = S021ReferrerPolicyAnalyzer._weakPolicies
82
+ .any((p) => source.contains(p));
83
+
84
+ if (hasWeakPolicy) {
85
+ violations.add(analyzer.createViolation(
86
+ filePath: filePath,
87
+ line: analyzer.getLine(lineInfo, node.offset),
88
+ column: analyzer.getColumn(lineInfo, node.offset),
89
+ message:
90
+ 'Weak Referrer-Policy - use strict-origin-when-cross-origin or stricter policy',
91
+ ));
92
+ }
93
+ }
94
+
95
+ super.visitMethodInvocation(node);
96
+ }
97
+
98
+ @override
99
+ void visitMapLiteralEntry(MapLiteralEntry node) {
100
+ final key = node.key.toSource().toLowerCase();
101
+ final value = node.value.toSource().toLowerCase();
102
+
103
+ // Check for Referrer-Policy header
104
+ if (key.contains('referrer-policy') || key.contains('referrerpolicy')) {
105
+ // Check for weak policies
106
+ bool hasWeakPolicy = S021ReferrerPolicyAnalyzer._weakPolicies
107
+ .any((p) => value.contains(p));
108
+
109
+ if (hasWeakPolicy) {
110
+ violations.add(analyzer.createViolation(
111
+ filePath: filePath,
112
+ line: analyzer.getLine(lineInfo, node.offset),
113
+ column: analyzer.getColumn(lineInfo, node.offset),
114
+ message:
115
+ 'Weak Referrer-Policy "$value" - use strict-origin-when-cross-origin instead',
116
+ ));
117
+ }
118
+ }
119
+
120
+ super.visitMapLiteralEntry(node);
121
+ }
122
+
123
+ @override
124
+ void visitAssignmentExpression(AssignmentExpression node) {
125
+ final left = node.leftHandSide.toSource().toLowerCase();
126
+ final right = node.rightHandSide.toSource().toLowerCase();
127
+
128
+ // Check for referrer policy assignments
129
+ if (left.contains('referrer')) {
130
+ bool hasWeakPolicy = S021ReferrerPolicyAnalyzer._weakPolicies
131
+ .any((p) => right.contains(p));
132
+
133
+ if (hasWeakPolicy) {
134
+ violations.add(analyzer.createViolation(
135
+ filePath: filePath,
136
+ line: analyzer.getLine(lineInfo, node.offset),
137
+ column: analyzer.getColumn(lineInfo, node.offset),
138
+ message:
139
+ 'Weak Referrer-Policy setting - use strict-origin-when-cross-origin or no-referrer',
140
+ ));
141
+ }
142
+ }
143
+
144
+ super.visitAssignmentExpression(node);
145
+ }
146
+ }
@@ -0,0 +1,111 @@
1
+ import 'package:analyzer/dart/ast/ast.dart';
2
+ import 'package:analyzer/dart/ast/visitor.dart';
3
+ import 'package:analyzer/source/line_info.dart';
4
+
5
+ import '../../models/rule.dart';
6
+ import '../../models/violation.dart';
7
+ import '../base_analyzer.dart';
8
+
9
+ /// S022: Escape Output Context
10
+ /// Ensure proper output encoding/escaping to prevent XSS
11
+ class S022EscapeOutputContextAnalyzer extends BaseAnalyzer {
12
+ @override
13
+ String get ruleId => 'S022';
14
+
15
+ // HTML output contexts
16
+ static const _htmlMethods = [
17
+ 'innerhtml', 'outerhtml', 'setinnerhtml', 'appendhtml',
18
+ 'insertadjacenthtml', 'document.write', 'createelement',
19
+ ];
20
+
21
+ @override
22
+ List<Violation> analyze({
23
+ required CompilationUnit unit,
24
+ required String filePath,
25
+ required Rule rule,
26
+ required LineInfo lineInfo,
27
+ }) {
28
+ final violations = <Violation>[];
29
+ final visitor = _S022Visitor(
30
+ filePath: filePath,
31
+ lineInfo: lineInfo,
32
+ violations: violations,
33
+ analyzer: this,
34
+ );
35
+ unit.accept(visitor);
36
+ return violations;
37
+ }
38
+ }
39
+
40
+ class _S022Visitor extends RecursiveAstVisitor<void> {
41
+ final String filePath;
42
+ final LineInfo lineInfo;
43
+ final List<Violation> violations;
44
+ final S022EscapeOutputContextAnalyzer analyzer;
45
+
46
+ _S022Visitor({
47
+ required this.filePath,
48
+ required this.lineInfo,
49
+ required this.violations,
50
+ required this.analyzer,
51
+ });
52
+
53
+ @override
54
+ void visitAssignmentExpression(AssignmentExpression node) {
55
+ final leftSide = node.leftHandSide.toSource().toLowerCase();
56
+
57
+ // Check for innerHTML assignment
58
+ if (S022EscapeOutputContextAnalyzer._htmlMethods.any((m) => leftSide.contains(m))) {
59
+ final rightSide = node.rightHandSide;
60
+
61
+ // Check if right side is user input (not sanitized)
62
+ if (rightSide is StringInterpolation || rightSide is SimpleIdentifier) {
63
+ final rightSource = rightSide.toSource().toLowerCase();
64
+ bool isSanitized = rightSource.contains('escape') ||
65
+ rightSource.contains('sanitize') ||
66
+ rightSource.contains('encode') ||
67
+ rightSource.contains('htmlescape');
68
+
69
+ if (!isSanitized) {
70
+ violations.add(analyzer.createViolation(
71
+ filePath: filePath,
72
+ line: analyzer.getLine(lineInfo, node.offset),
73
+ column: analyzer.getColumn(lineInfo, node.offset),
74
+ message: 'XSS risk - escape/sanitize user input before HTML output',
75
+ ));
76
+ }
77
+ }
78
+ }
79
+
80
+ super.visitAssignmentExpression(node);
81
+ }
82
+
83
+ @override
84
+ void visitMethodInvocation(MethodInvocation node) {
85
+ final methodName = node.methodName.name.toLowerCase();
86
+
87
+ // Check for HTML manipulation methods
88
+ if (S022EscapeOutputContextAnalyzer._htmlMethods.any((m) => methodName.contains(m))) {
89
+ for (final arg in node.argumentList.arguments) {
90
+ if (arg is StringInterpolation || arg is SimpleIdentifier) {
91
+ final source = arg.toSource().toLowerCase();
92
+ bool isSanitized = source.contains('escape') ||
93
+ source.contains('sanitize') ||
94
+ source.contains('encode');
95
+
96
+ if (!isSanitized) {
97
+ violations.add(analyzer.createViolation(
98
+ filePath: filePath,
99
+ line: analyzer.getLine(lineInfo, node.offset),
100
+ column: analyzer.getColumn(lineInfo, node.offset),
101
+ message: 'XSS risk - sanitize input before inserting into HTML',
102
+ ));
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ super.visitMethodInvocation(node);
110
+ }
111
+ }