@claude-flow/security 3.0.0-alpha.1 → 3.0.0-alpha.11

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 (150) hide show
  1. package/README.md +292 -234
  2. package/__tests__/acceptance/security-compliance.test.ts +674 -674
  3. package/__tests__/authorization-propagator.test.ts +155 -0
  4. package/__tests__/credential-generator.test.ts +310 -310
  5. package/__tests__/fixtures/configurations.ts +425 -419
  6. package/__tests__/fixtures/index.ts +21 -21
  7. package/__tests__/helpers/create-mock.ts +469 -469
  8. package/__tests__/helpers/index.ts +32 -32
  9. package/__tests__/input-validator.test.ts +382 -381
  10. package/__tests__/integration/security-flow.test.ts +606 -606
  11. package/__tests__/keychain-adapter.test.ts +60 -0
  12. package/__tests__/oauth-browser.test.ts +13 -0
  13. package/__tests__/oauth-export-surface.test.ts +21 -0
  14. package/__tests__/oauth-pkce.test.ts +37 -0
  15. package/__tests__/password-hasher.test.ts +239 -239
  16. package/__tests__/path-validator.test.ts +302 -302
  17. package/__tests__/plugin-integrity-verifier.test.ts +199 -0
  18. package/__tests__/safe-executor.test.ts +292 -292
  19. package/__tests__/token-generator.test.ts +371 -371
  20. package/__tests__/tool-output-guardrail.test.ts +256 -0
  21. package/__tests__/unit/credential-generator.test.ts +182 -182
  22. package/__tests__/unit/password-hasher.test.ts +359 -359
  23. package/__tests__/unit/path-validator.test.ts +509 -509
  24. package/__tests__/unit/safe-executor.test.ts +667 -667
  25. package/__tests__/unit/token-generator.test.ts +310 -310
  26. package/dist/CVE-REMEDIATION.d.ts +17 -6
  27. package/dist/CVE-REMEDIATION.d.ts.map +1 -1
  28. package/dist/CVE-REMEDIATION.js +328 -12
  29. package/dist/CVE-REMEDIATION.js.map +1 -1
  30. package/dist/authorization/propagator.d.ts +148 -0
  31. package/dist/authorization/propagator.d.ts.map +1 -0
  32. package/dist/authorization/propagator.js +182 -0
  33. package/dist/authorization/propagator.js.map +1 -0
  34. package/dist/credential-generator.js +9 -9
  35. package/dist/domain/services/security-domain-service.js +1 -1
  36. package/dist/domain/services/security-domain-service.js.map +1 -1
  37. package/dist/index.d.ts +9 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +21 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/keychain-adapter.d.ts +48 -0
  42. package/dist/keychain-adapter.d.ts.map +1 -0
  43. package/dist/keychain-adapter.js +0 -0
  44. package/dist/keychain-adapter.js.map +1 -0
  45. package/dist/oauth/browser.d.ts +31 -0
  46. package/dist/oauth/browser.d.ts.map +1 -0
  47. package/dist/oauth/browser.js +55 -0
  48. package/dist/oauth/browser.js.map +1 -0
  49. package/dist/oauth/callback-server.d.ts +37 -0
  50. package/dist/oauth/callback-server.d.ts.map +1 -0
  51. package/dist/oauth/callback-server.js +86 -0
  52. package/dist/oauth/callback-server.js.map +1 -0
  53. package/dist/oauth/client.d.ts +57 -0
  54. package/dist/oauth/client.d.ts.map +1 -0
  55. package/dist/oauth/client.js +120 -0
  56. package/dist/oauth/client.js.map +1 -0
  57. package/dist/oauth/pkce.d.ts +25 -0
  58. package/dist/oauth/pkce.d.ts.map +1 -0
  59. package/dist/oauth/pkce.js +36 -0
  60. package/dist/oauth/pkce.js.map +1 -0
  61. package/dist/password-hasher.d.ts.map +1 -1
  62. package/dist/password-hasher.js +8 -1
  63. package/dist/password-hasher.js.map +1 -1
  64. package/dist/plugins/integrity-verifier.d.ts +125 -0
  65. package/dist/plugins/integrity-verifier.d.ts.map +1 -0
  66. package/dist/plugins/integrity-verifier.js +186 -0
  67. package/dist/plugins/integrity-verifier.js.map +1 -0
  68. package/dist/safe-executor.d.ts +7 -0
  69. package/dist/safe-executor.d.ts.map +1 -1
  70. package/dist/safe-executor.js +21 -1
  71. package/dist/safe-executor.js.map +1 -1
  72. package/dist/tool-output-guardrail.d.ts +126 -0
  73. package/dist/tool-output-guardrail.d.ts.map +1 -0
  74. package/dist/tool-output-guardrail.js +257 -0
  75. package/dist/tool-output-guardrail.js.map +1 -0
  76. package/node_modules-incomplete-release-test/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  77. package/package.json +33 -28
  78. package/scripts/verify-oauth-exports.mjs +29 -0
  79. package/src/CVE-REMEDIATION.ts +591 -251
  80. package/src/application/index.ts +10 -10
  81. package/src/application/services/security-application-service.ts +193 -193
  82. package/src/authorization/propagator.ts +279 -0
  83. package/src/credential-generator.ts +368 -368
  84. package/src/domain/entities/security-context.ts +173 -173
  85. package/src/domain/index.ts +17 -17
  86. package/src/domain/services/security-domain-service.ts +296 -296
  87. package/src/index.ts +340 -271
  88. package/src/input-validator.ts +466 -466
  89. package/src/keychain-adapter.ts +0 -0
  90. package/src/oauth/browser.ts +58 -0
  91. package/src/oauth/callback-server.ts +97 -0
  92. package/src/oauth/client.ts +153 -0
  93. package/src/oauth/pkce.ts +45 -0
  94. package/src/password-hasher.ts +277 -270
  95. package/src/path-validator.ts +525 -525
  96. package/src/plugins/integrity-verifier.ts +265 -0
  97. package/src/safe-executor.ts +546 -525
  98. package/src/token-generator.ts +463 -463
  99. package/src/tool-output-guardrail.ts +360 -0
  100. package/tmp.json +0 -0
  101. package/tsconfig.json +9 -9
  102. package/tsconfig.tsbuildinfo +1 -1
  103. package/vitest.config.ts +20 -0
  104. package/.agentic-flow/intelligence.json +0 -16
  105. package/__tests__/coverage/base.css +0 -224
  106. package/__tests__/coverage/block-navigation.js +0 -87
  107. package/__tests__/coverage/coverage-final.json +0 -11
  108. package/__tests__/coverage/favicon.png +0 -0
  109. package/__tests__/coverage/index.html +0 -161
  110. package/__tests__/coverage/lcov-report/base.css +0 -224
  111. package/__tests__/coverage/lcov-report/block-navigation.js +0 -87
  112. package/__tests__/coverage/lcov-report/favicon.png +0 -0
  113. package/__tests__/coverage/lcov-report/index.html +0 -161
  114. package/__tests__/coverage/lcov-report/prettify.css +0 -1
  115. package/__tests__/coverage/lcov-report/prettify.js +0 -2
  116. package/__tests__/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  117. package/__tests__/coverage/lcov-report/sorter.js +0 -210
  118. package/__tests__/coverage/lcov-report/src/CVE-REMEDIATION.ts.html +0 -838
  119. package/__tests__/coverage/lcov-report/src/application/services/index.html +0 -116
  120. package/__tests__/coverage/lcov-report/src/application/services/security-application-service.ts.html +0 -664
  121. package/__tests__/coverage/lcov-report/src/credential-generator.ts.html +0 -1189
  122. package/__tests__/coverage/lcov-report/src/domain/entities/index.html +0 -116
  123. package/__tests__/coverage/lcov-report/src/domain/entities/security-context.ts.html +0 -604
  124. package/__tests__/coverage/lcov-report/src/domain/services/index.html +0 -116
  125. package/__tests__/coverage/lcov-report/src/domain/services/security-domain-service.ts.html +0 -973
  126. package/__tests__/coverage/lcov-report/src/index.html +0 -206
  127. package/__tests__/coverage/lcov-report/src/input-validator.ts.html +0 -1483
  128. package/__tests__/coverage/lcov-report/src/password-hasher.ts.html +0 -895
  129. package/__tests__/coverage/lcov-report/src/path-validator.ts.html +0 -1660
  130. package/__tests__/coverage/lcov-report/src/safe-executor.ts.html +0 -1660
  131. package/__tests__/coverage/lcov-report/src/token-generator.ts.html +0 -1474
  132. package/__tests__/coverage/lcov.info +0 -3650
  133. package/__tests__/coverage/prettify.css +0 -1
  134. package/__tests__/coverage/prettify.js +0 -2
  135. package/__tests__/coverage/sort-arrow-sprite.png +0 -0
  136. package/__tests__/coverage/sorter.js +0 -210
  137. package/__tests__/coverage/src/CVE-REMEDIATION.ts.html +0 -838
  138. package/__tests__/coverage/src/application/services/index.html +0 -116
  139. package/__tests__/coverage/src/application/services/security-application-service.ts.html +0 -664
  140. package/__tests__/coverage/src/credential-generator.ts.html +0 -1189
  141. package/__tests__/coverage/src/domain/entities/index.html +0 -116
  142. package/__tests__/coverage/src/domain/entities/security-context.ts.html +0 -604
  143. package/__tests__/coverage/src/domain/services/index.html +0 -116
  144. package/__tests__/coverage/src/domain/services/security-domain-service.ts.html +0 -973
  145. package/__tests__/coverage/src/index.html +0 -206
  146. package/__tests__/coverage/src/input-validator.ts.html +0 -1483
  147. package/__tests__/coverage/src/password-hasher.ts.html +0 -895
  148. package/__tests__/coverage/src/path-validator.ts.html +0 -1660
  149. package/__tests__/coverage/src/safe-executor.ts.html +0 -1660
  150. package/__tests__/coverage/src/token-generator.ts.html +0 -1474
@@ -1,895 +0,0 @@
1
-
2
- <!doctype html>
3
- <html lang="en">
4
-
5
- <head>
6
- <title>Code coverage report for src/password-hasher.ts</title>
7
- <meta charset="utf-8" />
8
- <link rel="stylesheet" href="../prettify.css" />
9
- <link rel="stylesheet" href="../base.css" />
10
- <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
- <meta name="viewport" content="width=device-width, initial-scale=1" />
12
- <style type='text/css'>
13
- .coverage-summary .sorter {
14
- background-image: url(../sort-arrow-sprite.png);
15
- }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <div class='wrapper'>
21
- <div class='pad1'>
22
- <h1><a href="../index.html">All files</a> / <a href="index.html">src</a> password-hasher.ts</h1>
23
- <div class='clearfix'>
24
-
25
- <div class='fl pad1y space-right2'>
26
- <span class="strong">0% </span>
27
- <span class="quiet">Statements</span>
28
- <span class='fraction'>0/270</span>
29
- </div>
30
-
31
-
32
- <div class='fl pad1y space-right2'>
33
- <span class="strong">0% </span>
34
- <span class="quiet">Branches</span>
35
- <span class='fraction'>0/1</span>
36
- </div>
37
-
38
-
39
- <div class='fl pad1y space-right2'>
40
- <span class="strong">0% </span>
41
- <span class="quiet">Functions</span>
42
- <span class='fraction'>0/1</span>
43
- </div>
44
-
45
-
46
- <div class='fl pad1y space-right2'>
47
- <span class="strong">0% </span>
48
- <span class="quiet">Lines</span>
49
- <span class='fraction'>0/270</span>
50
- </div>
51
-
52
-
53
- </div>
54
- <p class="quiet">
55
- Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
- </p>
57
- <template id="filterTemplate">
58
- <div class="quiet">
59
- Filter:
60
- <input type="search" id="fileSearch">
61
- </div>
62
- </template>
63
- </div>
64
- <div class='status-line low'></div>
65
- <pre><table class="coverage">
66
- <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
- <a name='L2'></a><a href='#L2'>2</a>
68
- <a name='L3'></a><a href='#L3'>3</a>
69
- <a name='L4'></a><a href='#L4'>4</a>
70
- <a name='L5'></a><a href='#L5'>5</a>
71
- <a name='L6'></a><a href='#L6'>6</a>
72
- <a name='L7'></a><a href='#L7'>7</a>
73
- <a name='L8'></a><a href='#L8'>8</a>
74
- <a name='L9'></a><a href='#L9'>9</a>
75
- <a name='L10'></a><a href='#L10'>10</a>
76
- <a name='L11'></a><a href='#L11'>11</a>
77
- <a name='L12'></a><a href='#L12'>12</a>
78
- <a name='L13'></a><a href='#L13'>13</a>
79
- <a name='L14'></a><a href='#L14'>14</a>
80
- <a name='L15'></a><a href='#L15'>15</a>
81
- <a name='L16'></a><a href='#L16'>16</a>
82
- <a name='L17'></a><a href='#L17'>17</a>
83
- <a name='L18'></a><a href='#L18'>18</a>
84
- <a name='L19'></a><a href='#L19'>19</a>
85
- <a name='L20'></a><a href='#L20'>20</a>
86
- <a name='L21'></a><a href='#L21'>21</a>
87
- <a name='L22'></a><a href='#L22'>22</a>
88
- <a name='L23'></a><a href='#L23'>23</a>
89
- <a name='L24'></a><a href='#L24'>24</a>
90
- <a name='L25'></a><a href='#L25'>25</a>
91
- <a name='L26'></a><a href='#L26'>26</a>
92
- <a name='L27'></a><a href='#L27'>27</a>
93
- <a name='L28'></a><a href='#L28'>28</a>
94
- <a name='L29'></a><a href='#L29'>29</a>
95
- <a name='L30'></a><a href='#L30'>30</a>
96
- <a name='L31'></a><a href='#L31'>31</a>
97
- <a name='L32'></a><a href='#L32'>32</a>
98
- <a name='L33'></a><a href='#L33'>33</a>
99
- <a name='L34'></a><a href='#L34'>34</a>
100
- <a name='L35'></a><a href='#L35'>35</a>
101
- <a name='L36'></a><a href='#L36'>36</a>
102
- <a name='L37'></a><a href='#L37'>37</a>
103
- <a name='L38'></a><a href='#L38'>38</a>
104
- <a name='L39'></a><a href='#L39'>39</a>
105
- <a name='L40'></a><a href='#L40'>40</a>
106
- <a name='L41'></a><a href='#L41'>41</a>
107
- <a name='L42'></a><a href='#L42'>42</a>
108
- <a name='L43'></a><a href='#L43'>43</a>
109
- <a name='L44'></a><a href='#L44'>44</a>
110
- <a name='L45'></a><a href='#L45'>45</a>
111
- <a name='L46'></a><a href='#L46'>46</a>
112
- <a name='L47'></a><a href='#L47'>47</a>
113
- <a name='L48'></a><a href='#L48'>48</a>
114
- <a name='L49'></a><a href='#L49'>49</a>
115
- <a name='L50'></a><a href='#L50'>50</a>
116
- <a name='L51'></a><a href='#L51'>51</a>
117
- <a name='L52'></a><a href='#L52'>52</a>
118
- <a name='L53'></a><a href='#L53'>53</a>
119
- <a name='L54'></a><a href='#L54'>54</a>
120
- <a name='L55'></a><a href='#L55'>55</a>
121
- <a name='L56'></a><a href='#L56'>56</a>
122
- <a name='L57'></a><a href='#L57'>57</a>
123
- <a name='L58'></a><a href='#L58'>58</a>
124
- <a name='L59'></a><a href='#L59'>59</a>
125
- <a name='L60'></a><a href='#L60'>60</a>
126
- <a name='L61'></a><a href='#L61'>61</a>
127
- <a name='L62'></a><a href='#L62'>62</a>
128
- <a name='L63'></a><a href='#L63'>63</a>
129
- <a name='L64'></a><a href='#L64'>64</a>
130
- <a name='L65'></a><a href='#L65'>65</a>
131
- <a name='L66'></a><a href='#L66'>66</a>
132
- <a name='L67'></a><a href='#L67'>67</a>
133
- <a name='L68'></a><a href='#L68'>68</a>
134
- <a name='L69'></a><a href='#L69'>69</a>
135
- <a name='L70'></a><a href='#L70'>70</a>
136
- <a name='L71'></a><a href='#L71'>71</a>
137
- <a name='L72'></a><a href='#L72'>72</a>
138
- <a name='L73'></a><a href='#L73'>73</a>
139
- <a name='L74'></a><a href='#L74'>74</a>
140
- <a name='L75'></a><a href='#L75'>75</a>
141
- <a name='L76'></a><a href='#L76'>76</a>
142
- <a name='L77'></a><a href='#L77'>77</a>
143
- <a name='L78'></a><a href='#L78'>78</a>
144
- <a name='L79'></a><a href='#L79'>79</a>
145
- <a name='L80'></a><a href='#L80'>80</a>
146
- <a name='L81'></a><a href='#L81'>81</a>
147
- <a name='L82'></a><a href='#L82'>82</a>
148
- <a name='L83'></a><a href='#L83'>83</a>
149
- <a name='L84'></a><a href='#L84'>84</a>
150
- <a name='L85'></a><a href='#L85'>85</a>
151
- <a name='L86'></a><a href='#L86'>86</a>
152
- <a name='L87'></a><a href='#L87'>87</a>
153
- <a name='L88'></a><a href='#L88'>88</a>
154
- <a name='L89'></a><a href='#L89'>89</a>
155
- <a name='L90'></a><a href='#L90'>90</a>
156
- <a name='L91'></a><a href='#L91'>91</a>
157
- <a name='L92'></a><a href='#L92'>92</a>
158
- <a name='L93'></a><a href='#L93'>93</a>
159
- <a name='L94'></a><a href='#L94'>94</a>
160
- <a name='L95'></a><a href='#L95'>95</a>
161
- <a name='L96'></a><a href='#L96'>96</a>
162
- <a name='L97'></a><a href='#L97'>97</a>
163
- <a name='L98'></a><a href='#L98'>98</a>
164
- <a name='L99'></a><a href='#L99'>99</a>
165
- <a name='L100'></a><a href='#L100'>100</a>
166
- <a name='L101'></a><a href='#L101'>101</a>
167
- <a name='L102'></a><a href='#L102'>102</a>
168
- <a name='L103'></a><a href='#L103'>103</a>
169
- <a name='L104'></a><a href='#L104'>104</a>
170
- <a name='L105'></a><a href='#L105'>105</a>
171
- <a name='L106'></a><a href='#L106'>106</a>
172
- <a name='L107'></a><a href='#L107'>107</a>
173
- <a name='L108'></a><a href='#L108'>108</a>
174
- <a name='L109'></a><a href='#L109'>109</a>
175
- <a name='L110'></a><a href='#L110'>110</a>
176
- <a name='L111'></a><a href='#L111'>111</a>
177
- <a name='L112'></a><a href='#L112'>112</a>
178
- <a name='L113'></a><a href='#L113'>113</a>
179
- <a name='L114'></a><a href='#L114'>114</a>
180
- <a name='L115'></a><a href='#L115'>115</a>
181
- <a name='L116'></a><a href='#L116'>116</a>
182
- <a name='L117'></a><a href='#L117'>117</a>
183
- <a name='L118'></a><a href='#L118'>118</a>
184
- <a name='L119'></a><a href='#L119'>119</a>
185
- <a name='L120'></a><a href='#L120'>120</a>
186
- <a name='L121'></a><a href='#L121'>121</a>
187
- <a name='L122'></a><a href='#L122'>122</a>
188
- <a name='L123'></a><a href='#L123'>123</a>
189
- <a name='L124'></a><a href='#L124'>124</a>
190
- <a name='L125'></a><a href='#L125'>125</a>
191
- <a name='L126'></a><a href='#L126'>126</a>
192
- <a name='L127'></a><a href='#L127'>127</a>
193
- <a name='L128'></a><a href='#L128'>128</a>
194
- <a name='L129'></a><a href='#L129'>129</a>
195
- <a name='L130'></a><a href='#L130'>130</a>
196
- <a name='L131'></a><a href='#L131'>131</a>
197
- <a name='L132'></a><a href='#L132'>132</a>
198
- <a name='L133'></a><a href='#L133'>133</a>
199
- <a name='L134'></a><a href='#L134'>134</a>
200
- <a name='L135'></a><a href='#L135'>135</a>
201
- <a name='L136'></a><a href='#L136'>136</a>
202
- <a name='L137'></a><a href='#L137'>137</a>
203
- <a name='L138'></a><a href='#L138'>138</a>
204
- <a name='L139'></a><a href='#L139'>139</a>
205
- <a name='L140'></a><a href='#L140'>140</a>
206
- <a name='L141'></a><a href='#L141'>141</a>
207
- <a name='L142'></a><a href='#L142'>142</a>
208
- <a name='L143'></a><a href='#L143'>143</a>
209
- <a name='L144'></a><a href='#L144'>144</a>
210
- <a name='L145'></a><a href='#L145'>145</a>
211
- <a name='L146'></a><a href='#L146'>146</a>
212
- <a name='L147'></a><a href='#L147'>147</a>
213
- <a name='L148'></a><a href='#L148'>148</a>
214
- <a name='L149'></a><a href='#L149'>149</a>
215
- <a name='L150'></a><a href='#L150'>150</a>
216
- <a name='L151'></a><a href='#L151'>151</a>
217
- <a name='L152'></a><a href='#L152'>152</a>
218
- <a name='L153'></a><a href='#L153'>153</a>
219
- <a name='L154'></a><a href='#L154'>154</a>
220
- <a name='L155'></a><a href='#L155'>155</a>
221
- <a name='L156'></a><a href='#L156'>156</a>
222
- <a name='L157'></a><a href='#L157'>157</a>
223
- <a name='L158'></a><a href='#L158'>158</a>
224
- <a name='L159'></a><a href='#L159'>159</a>
225
- <a name='L160'></a><a href='#L160'>160</a>
226
- <a name='L161'></a><a href='#L161'>161</a>
227
- <a name='L162'></a><a href='#L162'>162</a>
228
- <a name='L163'></a><a href='#L163'>163</a>
229
- <a name='L164'></a><a href='#L164'>164</a>
230
- <a name='L165'></a><a href='#L165'>165</a>
231
- <a name='L166'></a><a href='#L166'>166</a>
232
- <a name='L167'></a><a href='#L167'>167</a>
233
- <a name='L168'></a><a href='#L168'>168</a>
234
- <a name='L169'></a><a href='#L169'>169</a>
235
- <a name='L170'></a><a href='#L170'>170</a>
236
- <a name='L171'></a><a href='#L171'>171</a>
237
- <a name='L172'></a><a href='#L172'>172</a>
238
- <a name='L173'></a><a href='#L173'>173</a>
239
- <a name='L174'></a><a href='#L174'>174</a>
240
- <a name='L175'></a><a href='#L175'>175</a>
241
- <a name='L176'></a><a href='#L176'>176</a>
242
- <a name='L177'></a><a href='#L177'>177</a>
243
- <a name='L178'></a><a href='#L178'>178</a>
244
- <a name='L179'></a><a href='#L179'>179</a>
245
- <a name='L180'></a><a href='#L180'>180</a>
246
- <a name='L181'></a><a href='#L181'>181</a>
247
- <a name='L182'></a><a href='#L182'>182</a>
248
- <a name='L183'></a><a href='#L183'>183</a>
249
- <a name='L184'></a><a href='#L184'>184</a>
250
- <a name='L185'></a><a href='#L185'>185</a>
251
- <a name='L186'></a><a href='#L186'>186</a>
252
- <a name='L187'></a><a href='#L187'>187</a>
253
- <a name='L188'></a><a href='#L188'>188</a>
254
- <a name='L189'></a><a href='#L189'>189</a>
255
- <a name='L190'></a><a href='#L190'>190</a>
256
- <a name='L191'></a><a href='#L191'>191</a>
257
- <a name='L192'></a><a href='#L192'>192</a>
258
- <a name='L193'></a><a href='#L193'>193</a>
259
- <a name='L194'></a><a href='#L194'>194</a>
260
- <a name='L195'></a><a href='#L195'>195</a>
261
- <a name='L196'></a><a href='#L196'>196</a>
262
- <a name='L197'></a><a href='#L197'>197</a>
263
- <a name='L198'></a><a href='#L198'>198</a>
264
- <a name='L199'></a><a href='#L199'>199</a>
265
- <a name='L200'></a><a href='#L200'>200</a>
266
- <a name='L201'></a><a href='#L201'>201</a>
267
- <a name='L202'></a><a href='#L202'>202</a>
268
- <a name='L203'></a><a href='#L203'>203</a>
269
- <a name='L204'></a><a href='#L204'>204</a>
270
- <a name='L205'></a><a href='#L205'>205</a>
271
- <a name='L206'></a><a href='#L206'>206</a>
272
- <a name='L207'></a><a href='#L207'>207</a>
273
- <a name='L208'></a><a href='#L208'>208</a>
274
- <a name='L209'></a><a href='#L209'>209</a>
275
- <a name='L210'></a><a href='#L210'>210</a>
276
- <a name='L211'></a><a href='#L211'>211</a>
277
- <a name='L212'></a><a href='#L212'>212</a>
278
- <a name='L213'></a><a href='#L213'>213</a>
279
- <a name='L214'></a><a href='#L214'>214</a>
280
- <a name='L215'></a><a href='#L215'>215</a>
281
- <a name='L216'></a><a href='#L216'>216</a>
282
- <a name='L217'></a><a href='#L217'>217</a>
283
- <a name='L218'></a><a href='#L218'>218</a>
284
- <a name='L219'></a><a href='#L219'>219</a>
285
- <a name='L220'></a><a href='#L220'>220</a>
286
- <a name='L221'></a><a href='#L221'>221</a>
287
- <a name='L222'></a><a href='#L222'>222</a>
288
- <a name='L223'></a><a href='#L223'>223</a>
289
- <a name='L224'></a><a href='#L224'>224</a>
290
- <a name='L225'></a><a href='#L225'>225</a>
291
- <a name='L226'></a><a href='#L226'>226</a>
292
- <a name='L227'></a><a href='#L227'>227</a>
293
- <a name='L228'></a><a href='#L228'>228</a>
294
- <a name='L229'></a><a href='#L229'>229</a>
295
- <a name='L230'></a><a href='#L230'>230</a>
296
- <a name='L231'></a><a href='#L231'>231</a>
297
- <a name='L232'></a><a href='#L232'>232</a>
298
- <a name='L233'></a><a href='#L233'>233</a>
299
- <a name='L234'></a><a href='#L234'>234</a>
300
- <a name='L235'></a><a href='#L235'>235</a>
301
- <a name='L236'></a><a href='#L236'>236</a>
302
- <a name='L237'></a><a href='#L237'>237</a>
303
- <a name='L238'></a><a href='#L238'>238</a>
304
- <a name='L239'></a><a href='#L239'>239</a>
305
- <a name='L240'></a><a href='#L240'>240</a>
306
- <a name='L241'></a><a href='#L241'>241</a>
307
- <a name='L242'></a><a href='#L242'>242</a>
308
- <a name='L243'></a><a href='#L243'>243</a>
309
- <a name='L244'></a><a href='#L244'>244</a>
310
- <a name='L245'></a><a href='#L245'>245</a>
311
- <a name='L246'></a><a href='#L246'>246</a>
312
- <a name='L247'></a><a href='#L247'>247</a>
313
- <a name='L248'></a><a href='#L248'>248</a>
314
- <a name='L249'></a><a href='#L249'>249</a>
315
- <a name='L250'></a><a href='#L250'>250</a>
316
- <a name='L251'></a><a href='#L251'>251</a>
317
- <a name='L252'></a><a href='#L252'>252</a>
318
- <a name='L253'></a><a href='#L253'>253</a>
319
- <a name='L254'></a><a href='#L254'>254</a>
320
- <a name='L255'></a><a href='#L255'>255</a>
321
- <a name='L256'></a><a href='#L256'>256</a>
322
- <a name='L257'></a><a href='#L257'>257</a>
323
- <a name='L258'></a><a href='#L258'>258</a>
324
- <a name='L259'></a><a href='#L259'>259</a>
325
- <a name='L260'></a><a href='#L260'>260</a>
326
- <a name='L261'></a><a href='#L261'>261</a>
327
- <a name='L262'></a><a href='#L262'>262</a>
328
- <a name='L263'></a><a href='#L263'>263</a>
329
- <a name='L264'></a><a href='#L264'>264</a>
330
- <a name='L265'></a><a href='#L265'>265</a>
331
- <a name='L266'></a><a href='#L266'>266</a>
332
- <a name='L267'></a><a href='#L267'>267</a>
333
- <a name='L268'></a><a href='#L268'>268</a>
334
- <a name='L269'></a><a href='#L269'>269</a>
335
- <a name='L270'></a><a href='#L270'>270</a>
336
- <a name='L271'></a><a href='#L271'>271</a></td><td class="line-coverage quiet"><span class="cline-any cline-no">&nbsp;</span>
337
- <span class="cline-any cline-no">&nbsp;</span>
338
- <span class="cline-any cline-no">&nbsp;</span>
339
- <span class="cline-any cline-no">&nbsp;</span>
340
- <span class="cline-any cline-no">&nbsp;</span>
341
- <span class="cline-any cline-no">&nbsp;</span>
342
- <span class="cline-any cline-no">&nbsp;</span>
343
- <span class="cline-any cline-no">&nbsp;</span>
344
- <span class="cline-any cline-no">&nbsp;</span>
345
- <span class="cline-any cline-no">&nbsp;</span>
346
- <span class="cline-any cline-no">&nbsp;</span>
347
- <span class="cline-any cline-no">&nbsp;</span>
348
- <span class="cline-any cline-no">&nbsp;</span>
349
- <span class="cline-any cline-no">&nbsp;</span>
350
- <span class="cline-any cline-no">&nbsp;</span>
351
- <span class="cline-any cline-no">&nbsp;</span>
352
- <span class="cline-any cline-no">&nbsp;</span>
353
- <span class="cline-any cline-no">&nbsp;</span>
354
- <span class="cline-any cline-no">&nbsp;</span>
355
- <span class="cline-any cline-no">&nbsp;</span>
356
- <span class="cline-any cline-no">&nbsp;</span>
357
- <span class="cline-any cline-no">&nbsp;</span>
358
- <span class="cline-any cline-no">&nbsp;</span>
359
- <span class="cline-any cline-no">&nbsp;</span>
360
- <span class="cline-any cline-no">&nbsp;</span>
361
- <span class="cline-any cline-no">&nbsp;</span>
362
- <span class="cline-any cline-no">&nbsp;</span>
363
- <span class="cline-any cline-no">&nbsp;</span>
364
- <span class="cline-any cline-no">&nbsp;</span>
365
- <span class="cline-any cline-no">&nbsp;</span>
366
- <span class="cline-any cline-no">&nbsp;</span>
367
- <span class="cline-any cline-no">&nbsp;</span>
368
- <span class="cline-any cline-no">&nbsp;</span>
369
- <span class="cline-any cline-no">&nbsp;</span>
370
- <span class="cline-any cline-no">&nbsp;</span>
371
- <span class="cline-any cline-no">&nbsp;</span>
372
- <span class="cline-any cline-no">&nbsp;</span>
373
- <span class="cline-any cline-no">&nbsp;</span>
374
- <span class="cline-any cline-no">&nbsp;</span>
375
- <span class="cline-any cline-no">&nbsp;</span>
376
- <span class="cline-any cline-no">&nbsp;</span>
377
- <span class="cline-any cline-no">&nbsp;</span>
378
- <span class="cline-any cline-no">&nbsp;</span>
379
- <span class="cline-any cline-no">&nbsp;</span>
380
- <span class="cline-any cline-no">&nbsp;</span>
381
- <span class="cline-any cline-no">&nbsp;</span>
382
- <span class="cline-any cline-no">&nbsp;</span>
383
- <span class="cline-any cline-no">&nbsp;</span>
384
- <span class="cline-any cline-no">&nbsp;</span>
385
- <span class="cline-any cline-no">&nbsp;</span>
386
- <span class="cline-any cline-no">&nbsp;</span>
387
- <span class="cline-any cline-no">&nbsp;</span>
388
- <span class="cline-any cline-no">&nbsp;</span>
389
- <span class="cline-any cline-no">&nbsp;</span>
390
- <span class="cline-any cline-no">&nbsp;</span>
391
- <span class="cline-any cline-no">&nbsp;</span>
392
- <span class="cline-any cline-no">&nbsp;</span>
393
- <span class="cline-any cline-no">&nbsp;</span>
394
- <span class="cline-any cline-no">&nbsp;</span>
395
- <span class="cline-any cline-no">&nbsp;</span>
396
- <span class="cline-any cline-no">&nbsp;</span>
397
- <span class="cline-any cline-no">&nbsp;</span>
398
- <span class="cline-any cline-no">&nbsp;</span>
399
- <span class="cline-any cline-no">&nbsp;</span>
400
- <span class="cline-any cline-no">&nbsp;</span>
401
- <span class="cline-any cline-no">&nbsp;</span>
402
- <span class="cline-any cline-no">&nbsp;</span>
403
- <span class="cline-any cline-no">&nbsp;</span>
404
- <span class="cline-any cline-no">&nbsp;</span>
405
- <span class="cline-any cline-no">&nbsp;</span>
406
- <span class="cline-any cline-no">&nbsp;</span>
407
- <span class="cline-any cline-no">&nbsp;</span>
408
- <span class="cline-any cline-no">&nbsp;</span>
409
- <span class="cline-any cline-no">&nbsp;</span>
410
- <span class="cline-any cline-no">&nbsp;</span>
411
- <span class="cline-any cline-no">&nbsp;</span>
412
- <span class="cline-any cline-no">&nbsp;</span>
413
- <span class="cline-any cline-no">&nbsp;</span>
414
- <span class="cline-any cline-no">&nbsp;</span>
415
- <span class="cline-any cline-no">&nbsp;</span>
416
- <span class="cline-any cline-no">&nbsp;</span>
417
- <span class="cline-any cline-no">&nbsp;</span>
418
- <span class="cline-any cline-no">&nbsp;</span>
419
- <span class="cline-any cline-no">&nbsp;</span>
420
- <span class="cline-any cline-no">&nbsp;</span>
421
- <span class="cline-any cline-no">&nbsp;</span>
422
- <span class="cline-any cline-no">&nbsp;</span>
423
- <span class="cline-any cline-no">&nbsp;</span>
424
- <span class="cline-any cline-no">&nbsp;</span>
425
- <span class="cline-any cline-no">&nbsp;</span>
426
- <span class="cline-any cline-no">&nbsp;</span>
427
- <span class="cline-any cline-no">&nbsp;</span>
428
- <span class="cline-any cline-no">&nbsp;</span>
429
- <span class="cline-any cline-no">&nbsp;</span>
430
- <span class="cline-any cline-no">&nbsp;</span>
431
- <span class="cline-any cline-no">&nbsp;</span>
432
- <span class="cline-any cline-no">&nbsp;</span>
433
- <span class="cline-any cline-no">&nbsp;</span>
434
- <span class="cline-any cline-no">&nbsp;</span>
435
- <span class="cline-any cline-no">&nbsp;</span>
436
- <span class="cline-any cline-no">&nbsp;</span>
437
- <span class="cline-any cline-no">&nbsp;</span>
438
- <span class="cline-any cline-no">&nbsp;</span>
439
- <span class="cline-any cline-no">&nbsp;</span>
440
- <span class="cline-any cline-no">&nbsp;</span>
441
- <span class="cline-any cline-no">&nbsp;</span>
442
- <span class="cline-any cline-no">&nbsp;</span>
443
- <span class="cline-any cline-no">&nbsp;</span>
444
- <span class="cline-any cline-no">&nbsp;</span>
445
- <span class="cline-any cline-no">&nbsp;</span>
446
- <span class="cline-any cline-no">&nbsp;</span>
447
- <span class="cline-any cline-no">&nbsp;</span>
448
- <span class="cline-any cline-no">&nbsp;</span>
449
- <span class="cline-any cline-no">&nbsp;</span>
450
- <span class="cline-any cline-no">&nbsp;</span>
451
- <span class="cline-any cline-no">&nbsp;</span>
452
- <span class="cline-any cline-no">&nbsp;</span>
453
- <span class="cline-any cline-no">&nbsp;</span>
454
- <span class="cline-any cline-no">&nbsp;</span>
455
- <span class="cline-any cline-no">&nbsp;</span>
456
- <span class="cline-any cline-no">&nbsp;</span>
457
- <span class="cline-any cline-no">&nbsp;</span>
458
- <span class="cline-any cline-no">&nbsp;</span>
459
- <span class="cline-any cline-no">&nbsp;</span>
460
- <span class="cline-any cline-no">&nbsp;</span>
461
- <span class="cline-any cline-no">&nbsp;</span>
462
- <span class="cline-any cline-no">&nbsp;</span>
463
- <span class="cline-any cline-no">&nbsp;</span>
464
- <span class="cline-any cline-no">&nbsp;</span>
465
- <span class="cline-any cline-no">&nbsp;</span>
466
- <span class="cline-any cline-no">&nbsp;</span>
467
- <span class="cline-any cline-no">&nbsp;</span>
468
- <span class="cline-any cline-no">&nbsp;</span>
469
- <span class="cline-any cline-no">&nbsp;</span>
470
- <span class="cline-any cline-no">&nbsp;</span>
471
- <span class="cline-any cline-no">&nbsp;</span>
472
- <span class="cline-any cline-no">&nbsp;</span>
473
- <span class="cline-any cline-no">&nbsp;</span>
474
- <span class="cline-any cline-no">&nbsp;</span>
475
- <span class="cline-any cline-no">&nbsp;</span>
476
- <span class="cline-any cline-no">&nbsp;</span>
477
- <span class="cline-any cline-no">&nbsp;</span>
478
- <span class="cline-any cline-no">&nbsp;</span>
479
- <span class="cline-any cline-no">&nbsp;</span>
480
- <span class="cline-any cline-no">&nbsp;</span>
481
- <span class="cline-any cline-no">&nbsp;</span>
482
- <span class="cline-any cline-no">&nbsp;</span>
483
- <span class="cline-any cline-no">&nbsp;</span>
484
- <span class="cline-any cline-no">&nbsp;</span>
485
- <span class="cline-any cline-no">&nbsp;</span>
486
- <span class="cline-any cline-no">&nbsp;</span>
487
- <span class="cline-any cline-no">&nbsp;</span>
488
- <span class="cline-any cline-no">&nbsp;</span>
489
- <span class="cline-any cline-no">&nbsp;</span>
490
- <span class="cline-any cline-no">&nbsp;</span>
491
- <span class="cline-any cline-no">&nbsp;</span>
492
- <span class="cline-any cline-no">&nbsp;</span>
493
- <span class="cline-any cline-no">&nbsp;</span>
494
- <span class="cline-any cline-no">&nbsp;</span>
495
- <span class="cline-any cline-no">&nbsp;</span>
496
- <span class="cline-any cline-no">&nbsp;</span>
497
- <span class="cline-any cline-no">&nbsp;</span>
498
- <span class="cline-any cline-no">&nbsp;</span>
499
- <span class="cline-any cline-no">&nbsp;</span>
500
- <span class="cline-any cline-no">&nbsp;</span>
501
- <span class="cline-any cline-no">&nbsp;</span>
502
- <span class="cline-any cline-no">&nbsp;</span>
503
- <span class="cline-any cline-no">&nbsp;</span>
504
- <span class="cline-any cline-no">&nbsp;</span>
505
- <span class="cline-any cline-no">&nbsp;</span>
506
- <span class="cline-any cline-no">&nbsp;</span>
507
- <span class="cline-any cline-no">&nbsp;</span>
508
- <span class="cline-any cline-no">&nbsp;</span>
509
- <span class="cline-any cline-no">&nbsp;</span>
510
- <span class="cline-any cline-no">&nbsp;</span>
511
- <span class="cline-any cline-no">&nbsp;</span>
512
- <span class="cline-any cline-no">&nbsp;</span>
513
- <span class="cline-any cline-no">&nbsp;</span>
514
- <span class="cline-any cline-no">&nbsp;</span>
515
- <span class="cline-any cline-no">&nbsp;</span>
516
- <span class="cline-any cline-no">&nbsp;</span>
517
- <span class="cline-any cline-no">&nbsp;</span>
518
- <span class="cline-any cline-no">&nbsp;</span>
519
- <span class="cline-any cline-no">&nbsp;</span>
520
- <span class="cline-any cline-no">&nbsp;</span>
521
- <span class="cline-any cline-no">&nbsp;</span>
522
- <span class="cline-any cline-no">&nbsp;</span>
523
- <span class="cline-any cline-no">&nbsp;</span>
524
- <span class="cline-any cline-no">&nbsp;</span>
525
- <span class="cline-any cline-no">&nbsp;</span>
526
- <span class="cline-any cline-no">&nbsp;</span>
527
- <span class="cline-any cline-no">&nbsp;</span>
528
- <span class="cline-any cline-no">&nbsp;</span>
529
- <span class="cline-any cline-no">&nbsp;</span>
530
- <span class="cline-any cline-no">&nbsp;</span>
531
- <span class="cline-any cline-no">&nbsp;</span>
532
- <span class="cline-any cline-no">&nbsp;</span>
533
- <span class="cline-any cline-no">&nbsp;</span>
534
- <span class="cline-any cline-no">&nbsp;</span>
535
- <span class="cline-any cline-no">&nbsp;</span>
536
- <span class="cline-any cline-no">&nbsp;</span>
537
- <span class="cline-any cline-no">&nbsp;</span>
538
- <span class="cline-any cline-no">&nbsp;</span>
539
- <span class="cline-any cline-no">&nbsp;</span>
540
- <span class="cline-any cline-no">&nbsp;</span>
541
- <span class="cline-any cline-no">&nbsp;</span>
542
- <span class="cline-any cline-no">&nbsp;</span>
543
- <span class="cline-any cline-no">&nbsp;</span>
544
- <span class="cline-any cline-no">&nbsp;</span>
545
- <span class="cline-any cline-no">&nbsp;</span>
546
- <span class="cline-any cline-no">&nbsp;</span>
547
- <span class="cline-any cline-no">&nbsp;</span>
548
- <span class="cline-any cline-no">&nbsp;</span>
549
- <span class="cline-any cline-no">&nbsp;</span>
550
- <span class="cline-any cline-no">&nbsp;</span>
551
- <span class="cline-any cline-no">&nbsp;</span>
552
- <span class="cline-any cline-no">&nbsp;</span>
553
- <span class="cline-any cline-no">&nbsp;</span>
554
- <span class="cline-any cline-no">&nbsp;</span>
555
- <span class="cline-any cline-no">&nbsp;</span>
556
- <span class="cline-any cline-no">&nbsp;</span>
557
- <span class="cline-any cline-no">&nbsp;</span>
558
- <span class="cline-any cline-no">&nbsp;</span>
559
- <span class="cline-any cline-no">&nbsp;</span>
560
- <span class="cline-any cline-no">&nbsp;</span>
561
- <span class="cline-any cline-no">&nbsp;</span>
562
- <span class="cline-any cline-no">&nbsp;</span>
563
- <span class="cline-any cline-no">&nbsp;</span>
564
- <span class="cline-any cline-no">&nbsp;</span>
565
- <span class="cline-any cline-no">&nbsp;</span>
566
- <span class="cline-any cline-no">&nbsp;</span>
567
- <span class="cline-any cline-no">&nbsp;</span>
568
- <span class="cline-any cline-no">&nbsp;</span>
569
- <span class="cline-any cline-no">&nbsp;</span>
570
- <span class="cline-any cline-no">&nbsp;</span>
571
- <span class="cline-any cline-no">&nbsp;</span>
572
- <span class="cline-any cline-no">&nbsp;</span>
573
- <span class="cline-any cline-no">&nbsp;</span>
574
- <span class="cline-any cline-no">&nbsp;</span>
575
- <span class="cline-any cline-no">&nbsp;</span>
576
- <span class="cline-any cline-no">&nbsp;</span>
577
- <span class="cline-any cline-no">&nbsp;</span>
578
- <span class="cline-any cline-no">&nbsp;</span>
579
- <span class="cline-any cline-no">&nbsp;</span>
580
- <span class="cline-any cline-no">&nbsp;</span>
581
- <span class="cline-any cline-no">&nbsp;</span>
582
- <span class="cline-any cline-no">&nbsp;</span>
583
- <span class="cline-any cline-no">&nbsp;</span>
584
- <span class="cline-any cline-no">&nbsp;</span>
585
- <span class="cline-any cline-no">&nbsp;</span>
586
- <span class="cline-any cline-no">&nbsp;</span>
587
- <span class="cline-any cline-no">&nbsp;</span>
588
- <span class="cline-any cline-no">&nbsp;</span>
589
- <span class="cline-any cline-no">&nbsp;</span>
590
- <span class="cline-any cline-no">&nbsp;</span>
591
- <span class="cline-any cline-no">&nbsp;</span>
592
- <span class="cline-any cline-no">&nbsp;</span>
593
- <span class="cline-any cline-no">&nbsp;</span>
594
- <span class="cline-any cline-no">&nbsp;</span>
595
- <span class="cline-any cline-no">&nbsp;</span>
596
- <span class="cline-any cline-no">&nbsp;</span>
597
- <span class="cline-any cline-no">&nbsp;</span>
598
- <span class="cline-any cline-no">&nbsp;</span>
599
- <span class="cline-any cline-no">&nbsp;</span>
600
- <span class="cline-any cline-no">&nbsp;</span>
601
- <span class="cline-any cline-no">&nbsp;</span>
602
- <span class="cline-any cline-no">&nbsp;</span>
603
- <span class="cline-any cline-no">&nbsp;</span>
604
- <span class="cline-any cline-no">&nbsp;</span>
605
- <span class="cline-any cline-no">&nbsp;</span>
606
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" >/**<span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" ></span></span></span>
607
- <span class="cstat-no" title="statement not covered" > * Password Hasher - CVE-2 Remediation</span>
608
- <span class="cstat-no" title="statement not covered" > *</span>
609
- <span class="cstat-no" title="statement not covered" > * Fixes weak password hashing by replacing SHA-256 with hardcoded salt</span>
610
- <span class="cstat-no" title="statement not covered" > * with bcrypt using 12 rounds (configurable).</span>
611
- <span class="cstat-no" title="statement not covered" > *</span>
612
- <span class="cstat-no" title="statement not covered" > * Security Properties:</span>
613
- <span class="cstat-no" title="statement not covered" > * - bcrypt with adaptive cost factor (12 rounds)</span>
614
- <span class="cstat-no" title="statement not covered" > * - Automatic salt generation per password</span>
615
- <span class="cstat-no" title="statement not covered" > * - Timing-safe comparison</span>
616
- <span class="cstat-no" title="statement not covered" > * - Minimum password length enforcement</span>
617
- <span class="cstat-no" title="statement not covered" > *</span>
618
- <span class="cstat-no" title="statement not covered" > * @module v3/security/password-hasher</span>
619
- <span class="cstat-no" title="statement not covered" > */</span>
620
- <span class="cstat-no" title="statement not covered" ></span>
621
- <span class="cstat-no" title="statement not covered" >import * as bcrypt from 'bcrypt';</span>
622
- <span class="cstat-no" title="statement not covered" ></span>
623
- <span class="cstat-no" title="statement not covered" >export interface PasswordHasherConfig {</span>
624
- <span class="cstat-no" title="statement not covered" > /**</span>
625
- <span class="cstat-no" title="statement not covered" > * Number of bcrypt rounds (cost factor).</span>
626
- <span class="cstat-no" title="statement not covered" > * Default: 12 (recommended minimum for production)</span>
627
- <span class="cstat-no" title="statement not covered" > * Each increment doubles the computation time.</span>
628
- <span class="cstat-no" title="statement not covered" > */</span>
629
- <span class="cstat-no" title="statement not covered" > rounds?: number;</span>
630
- <span class="cstat-no" title="statement not covered" ></span>
631
- <span class="cstat-no" title="statement not covered" > /**</span>
632
- <span class="cstat-no" title="statement not covered" > * Minimum password length.</span>
633
- <span class="cstat-no" title="statement not covered" > * Default: 8 characters</span>
634
- <span class="cstat-no" title="statement not covered" > */</span>
635
- <span class="cstat-no" title="statement not covered" > minLength?: number;</span>
636
- <span class="cstat-no" title="statement not covered" ></span>
637
- <span class="cstat-no" title="statement not covered" > /**</span>
638
- <span class="cstat-no" title="statement not covered" > * Maximum password length.</span>
639
- <span class="cstat-no" title="statement not covered" > * Default: 128 characters (bcrypt limit is 72 bytes)</span>
640
- <span class="cstat-no" title="statement not covered" > */</span>
641
- <span class="cstat-no" title="statement not covered" > maxLength?: number;</span>
642
- <span class="cstat-no" title="statement not covered" ></span>
643
- <span class="cstat-no" title="statement not covered" > /**</span>
644
- <span class="cstat-no" title="statement not covered" > * Require at least one uppercase letter.</span>
645
- <span class="cstat-no" title="statement not covered" > * Default: true</span>
646
- <span class="cstat-no" title="statement not covered" > */</span>
647
- <span class="cstat-no" title="statement not covered" > requireUppercase?: boolean;</span>
648
- <span class="cstat-no" title="statement not covered" ></span>
649
- <span class="cstat-no" title="statement not covered" > /**</span>
650
- <span class="cstat-no" title="statement not covered" > * Require at least one lowercase letter.</span>
651
- <span class="cstat-no" title="statement not covered" > * Default: true</span>
652
- <span class="cstat-no" title="statement not covered" > */</span>
653
- <span class="cstat-no" title="statement not covered" > requireLowercase?: boolean;</span>
654
- <span class="cstat-no" title="statement not covered" ></span>
655
- <span class="cstat-no" title="statement not covered" > /**</span>
656
- <span class="cstat-no" title="statement not covered" > * Require at least one digit.</span>
657
- <span class="cstat-no" title="statement not covered" > * Default: true</span>
658
- <span class="cstat-no" title="statement not covered" > */</span>
659
- <span class="cstat-no" title="statement not covered" > requireDigit?: boolean;</span>
660
- <span class="cstat-no" title="statement not covered" ></span>
661
- <span class="cstat-no" title="statement not covered" > /**</span>
662
- <span class="cstat-no" title="statement not covered" > * Require at least one special character.</span>
663
- <span class="cstat-no" title="statement not covered" > * Default: false</span>
664
- <span class="cstat-no" title="statement not covered" > */</span>
665
- <span class="cstat-no" title="statement not covered" > requireSpecial?: boolean;</span>
666
- <span class="cstat-no" title="statement not covered" >}</span>
667
- <span class="cstat-no" title="statement not covered" ></span>
668
- <span class="cstat-no" title="statement not covered" >export interface PasswordValidationResult {</span>
669
- <span class="cstat-no" title="statement not covered" > isValid: boolean;</span>
670
- <span class="cstat-no" title="statement not covered" > errors: string[];</span>
671
- <span class="cstat-no" title="statement not covered" >}</span>
672
- <span class="cstat-no" title="statement not covered" ></span>
673
- <span class="cstat-no" title="statement not covered" >export class PasswordHashError extends Error {</span>
674
- <span class="cstat-no" title="statement not covered" > constructor(</span>
675
- <span class="cstat-no" title="statement not covered" > message: string,</span>
676
- <span class="cstat-no" title="statement not covered" > public readonly code: string,</span>
677
- <span class="cstat-no" title="statement not covered" > ) {</span>
678
- <span class="cstat-no" title="statement not covered" > super(message);</span>
679
- <span class="cstat-no" title="statement not covered" > this.name = 'PasswordHashError';</span>
680
- <span class="cstat-no" title="statement not covered" > }</span>
681
- <span class="cstat-no" title="statement not covered" >}</span>
682
- <span class="cstat-no" title="statement not covered" ></span>
683
- <span class="cstat-no" title="statement not covered" >/**</span>
684
- <span class="cstat-no" title="statement not covered" > * Secure password hasher using bcrypt.</span>
685
- <span class="cstat-no" title="statement not covered" > *</span>
686
- <span class="cstat-no" title="statement not covered" > * This class replaces the vulnerable SHA-256 + hardcoded salt implementation</span>
687
- <span class="cstat-no" title="statement not covered" > * with industry-standard bcrypt hashing.</span>
688
- <span class="cstat-no" title="statement not covered" > *</span>
689
- <span class="cstat-no" title="statement not covered" > * @example</span>
690
- <span class="cstat-no" title="statement not covered" > * ```typescript</span>
691
- <span class="cstat-no" title="statement not covered" > * const hasher = new PasswordHasher({ rounds: 12 });</span>
692
- <span class="cstat-no" title="statement not covered" > * const hash = await hasher.hash('securePassword123');</span>
693
- <span class="cstat-no" title="statement not covered" > * const isValid = await hasher.verify('securePassword123', hash);</span>
694
- <span class="cstat-no" title="statement not covered" > * ```</span>
695
- <span class="cstat-no" title="statement not covered" > */</span>
696
- <span class="cstat-no" title="statement not covered" >export class PasswordHasher {</span>
697
- <span class="cstat-no" title="statement not covered" > private readonly config: Required&lt;PasswordHasherConfig&gt;;</span>
698
- <span class="cstat-no" title="statement not covered" ></span>
699
- <span class="cstat-no" title="statement not covered" > constructor(config: PasswordHasherConfig = {}) {</span>
700
- <span class="cstat-no" title="statement not covered" > this.config = {</span>
701
- <span class="cstat-no" title="statement not covered" > rounds: config.rounds ?? 12,</span>
702
- <span class="cstat-no" title="statement not covered" > minLength: config.minLength ?? 8,</span>
703
- <span class="cstat-no" title="statement not covered" > maxLength: config.maxLength ?? 128,</span>
704
- <span class="cstat-no" title="statement not covered" > requireUppercase: config.requireUppercase ?? true,</span>
705
- <span class="cstat-no" title="statement not covered" > requireLowercase: config.requireLowercase ?? true,</span>
706
- <span class="cstat-no" title="statement not covered" > requireDigit: config.requireDigit ?? true,</span>
707
- <span class="cstat-no" title="statement not covered" > requireSpecial: config.requireSpecial ?? false,</span>
708
- <span class="cstat-no" title="statement not covered" > };</span>
709
- <span class="cstat-no" title="statement not covered" ></span>
710
- <span class="cstat-no" title="statement not covered" > // Validate configuration</span>
711
- <span class="cstat-no" title="statement not covered" > if (this.config.rounds &lt; 10 || this.config.rounds &gt; 20) {</span>
712
- <span class="cstat-no" title="statement not covered" > throw new PasswordHashError(</span>
713
- <span class="cstat-no" title="statement not covered" > 'Bcrypt rounds must be between 10 and 20 for security and performance balance',</span>
714
- <span class="cstat-no" title="statement not covered" > 'INVALID_ROUNDS'</span>
715
- <span class="cstat-no" title="statement not covered" > );</span>
716
- <span class="cstat-no" title="statement not covered" > }</span>
717
- <span class="cstat-no" title="statement not covered" ></span>
718
- <span class="cstat-no" title="statement not covered" > if (this.config.minLength &lt; 8) {</span>
719
- <span class="cstat-no" title="statement not covered" > throw new PasswordHashError(</span>
720
- <span class="cstat-no" title="statement not covered" > 'Minimum password length must be at least 8 characters',</span>
721
- <span class="cstat-no" title="statement not covered" > 'INVALID_MIN_LENGTH'</span>
722
- <span class="cstat-no" title="statement not covered" > );</span>
723
- <span class="cstat-no" title="statement not covered" > }</span>
724
- <span class="cstat-no" title="statement not covered" > }</span>
725
- <span class="cstat-no" title="statement not covered" ></span>
726
- <span class="cstat-no" title="statement not covered" > /**</span>
727
- <span class="cstat-no" title="statement not covered" > * Validates password against configured requirements.</span>
728
- <span class="cstat-no" title="statement not covered" > *</span>
729
- <span class="cstat-no" title="statement not covered" > * @param password - The password to validate</span>
730
- <span class="cstat-no" title="statement not covered" > * @returns Validation result with errors if any</span>
731
- <span class="cstat-no" title="statement not covered" > */</span>
732
- <span class="cstat-no" title="statement not covered" > validate(password: string): PasswordValidationResult {</span>
733
- <span class="cstat-no" title="statement not covered" > const errors: string[] = [];</span>
734
- <span class="cstat-no" title="statement not covered" ></span>
735
- <span class="cstat-no" title="statement not covered" > if (!password) {</span>
736
- <span class="cstat-no" title="statement not covered" > errors.push('Password is required');</span>
737
- <span class="cstat-no" title="statement not covered" > return { isValid: false, errors };</span>
738
- <span class="cstat-no" title="statement not covered" > }</span>
739
- <span class="cstat-no" title="statement not covered" ></span>
740
- <span class="cstat-no" title="statement not covered" > if (password.length &lt; this.config.minLength) {</span>
741
- <span class="cstat-no" title="statement not covered" > errors.push(`Password must be at least ${this.config.minLength} characters`);</span>
742
- <span class="cstat-no" title="statement not covered" > }</span>
743
- <span class="cstat-no" title="statement not covered" ></span>
744
- <span class="cstat-no" title="statement not covered" > if (password.length &gt; this.config.maxLength) {</span>
745
- <span class="cstat-no" title="statement not covered" > errors.push(`Password must not exceed ${this.config.maxLength} characters`);</span>
746
- <span class="cstat-no" title="statement not covered" > }</span>
747
- <span class="cstat-no" title="statement not covered" ></span>
748
- <span class="cstat-no" title="statement not covered" > if (this.config.requireUppercase &amp;&amp; !/[A-Z]/.test(password)) {</span>
749
- <span class="cstat-no" title="statement not covered" > errors.push('Password must contain at least one uppercase letter');</span>
750
- <span class="cstat-no" title="statement not covered" > }</span>
751
- <span class="cstat-no" title="statement not covered" ></span>
752
- <span class="cstat-no" title="statement not covered" > if (this.config.requireLowercase &amp;&amp; !/[a-z]/.test(password)) {</span>
753
- <span class="cstat-no" title="statement not covered" > errors.push('Password must contain at least one lowercase letter');</span>
754
- <span class="cstat-no" title="statement not covered" > }</span>
755
- <span class="cstat-no" title="statement not covered" ></span>
756
- <span class="cstat-no" title="statement not covered" > if (this.config.requireDigit &amp;&amp; !/\d/.test(password)) {</span>
757
- <span class="cstat-no" title="statement not covered" > errors.push('Password must contain at least one digit');</span>
758
- <span class="cstat-no" title="statement not covered" > }</span>
759
- <span class="cstat-no" title="statement not covered" ></span>
760
- <span class="cstat-no" title="statement not covered" > if (this.config.requireSpecial &amp;&amp; !/[!@#$%^&amp;*()_+\-=\[\]{};':"\\|,.&lt;&gt;\/?]/.test(password)) {</span>
761
- <span class="cstat-no" title="statement not covered" > errors.push('Password must contain at least one special character');</span>
762
- <span class="cstat-no" title="statement not covered" > }</span>
763
- <span class="cstat-no" title="statement not covered" ></span>
764
- <span class="cstat-no" title="statement not covered" > return {</span>
765
- <span class="cstat-no" title="statement not covered" > isValid: errors.length === 0,</span>
766
- <span class="cstat-no" title="statement not covered" > errors,</span>
767
- <span class="cstat-no" title="statement not covered" > };</span>
768
- <span class="cstat-no" title="statement not covered" > }</span>
769
- <span class="cstat-no" title="statement not covered" ></span>
770
- <span class="cstat-no" title="statement not covered" > /**</span>
771
- <span class="cstat-no" title="statement not covered" > * Hashes a password using bcrypt.</span>
772
- <span class="cstat-no" title="statement not covered" > *</span>
773
- <span class="cstat-no" title="statement not covered" > * @param password - The plaintext password to hash</span>
774
- <span class="cstat-no" title="statement not covered" > * @returns The bcrypt hash</span>
775
- <span class="cstat-no" title="statement not covered" > * @throws PasswordHashError if password is invalid</span>
776
- <span class="cstat-no" title="statement not covered" > */</span>
777
- <span class="cstat-no" title="statement not covered" > async hash(password: string): Promise&lt;string&gt; {</span>
778
- <span class="cstat-no" title="statement not covered" > const validation = this.validate(password);</span>
779
- <span class="cstat-no" title="statement not covered" ></span>
780
- <span class="cstat-no" title="statement not covered" > if (!validation.isValid) {</span>
781
- <span class="cstat-no" title="statement not covered" > throw new PasswordHashError(</span>
782
- <span class="cstat-no" title="statement not covered" > validation.errors.join('; '),</span>
783
- <span class="cstat-no" title="statement not covered" > 'VALIDATION_FAILED'</span>
784
- <span class="cstat-no" title="statement not covered" > );</span>
785
- <span class="cstat-no" title="statement not covered" > }</span>
786
- <span class="cstat-no" title="statement not covered" ></span>
787
- <span class="cstat-no" title="statement not covered" > try {</span>
788
- <span class="cstat-no" title="statement not covered" > // bcrypt automatically generates a random salt per hash</span>
789
- <span class="cstat-no" title="statement not covered" > return await bcrypt.hash(password, this.config.rounds);</span>
790
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
791
- <span class="cstat-no" title="statement not covered" > throw new PasswordHashError(</span>
792
- <span class="cstat-no" title="statement not covered" > 'Failed to hash password',</span>
793
- <span class="cstat-no" title="statement not covered" > 'HASH_FAILED'</span>
794
- <span class="cstat-no" title="statement not covered" > );</span>
795
- <span class="cstat-no" title="statement not covered" > }</span>
796
- <span class="cstat-no" title="statement not covered" > }</span>
797
- <span class="cstat-no" title="statement not covered" ></span>
798
- <span class="cstat-no" title="statement not covered" > /**</span>
799
- <span class="cstat-no" title="statement not covered" > * Verifies a password against a bcrypt hash.</span>
800
- <span class="cstat-no" title="statement not covered" > * Uses timing-safe comparison internally.</span>
801
- <span class="cstat-no" title="statement not covered" > *</span>
802
- <span class="cstat-no" title="statement not covered" > * @param password - The plaintext password to verify</span>
803
- <span class="cstat-no" title="statement not covered" > * @param hash - The bcrypt hash to compare against</span>
804
- <span class="cstat-no" title="statement not covered" > * @returns True if password matches, false otherwise</span>
805
- <span class="cstat-no" title="statement not covered" > */</span>
806
- <span class="cstat-no" title="statement not covered" > async verify(password: string, hash: string): Promise&lt;boolean&gt; {</span>
807
- <span class="cstat-no" title="statement not covered" > if (!password || !hash) {</span>
808
- <span class="cstat-no" title="statement not covered" > return false;</span>
809
- <span class="cstat-no" title="statement not covered" > }</span>
810
- <span class="cstat-no" title="statement not covered" ></span>
811
- <span class="cstat-no" title="statement not covered" > // Validate hash format (bcrypt hashes start with $2a$, $2b$, or $2y$)</span>
812
- <span class="cstat-no" title="statement not covered" > if (!this.isValidBcryptHash(hash)) {</span>
813
- <span class="cstat-no" title="statement not covered" > return false;</span>
814
- <span class="cstat-no" title="statement not covered" > }</span>
815
- <span class="cstat-no" title="statement not covered" ></span>
816
- <span class="cstat-no" title="statement not covered" > try {</span>
817
- <span class="cstat-no" title="statement not covered" > // bcrypt.compare uses timing-safe comparison</span>
818
- <span class="cstat-no" title="statement not covered" > return await bcrypt.compare(password, hash);</span>
819
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
820
- <span class="cstat-no" title="statement not covered" > // Return false on any error to prevent timing attacks</span>
821
- <span class="cstat-no" title="statement not covered" > return false;</span>
822
- <span class="cstat-no" title="statement not covered" > }</span>
823
- <span class="cstat-no" title="statement not covered" > }</span>
824
- <span class="cstat-no" title="statement not covered" ></span>
825
- <span class="cstat-no" title="statement not covered" > /**</span>
826
- <span class="cstat-no" title="statement not covered" > * Checks if a hash needs to be rehashed with updated parameters.</span>
827
- <span class="cstat-no" title="statement not covered" > * Useful for upgrading hash strength over time.</span>
828
- <span class="cstat-no" title="statement not covered" > *</span>
829
- <span class="cstat-no" title="statement not covered" > * @param hash - The bcrypt hash to check</span>
830
- <span class="cstat-no" title="statement not covered" > * @returns True if hash should be updated</span>
831
- <span class="cstat-no" title="statement not covered" > */</span>
832
- <span class="cstat-no" title="statement not covered" > needsRehash(hash: string): boolean {</span>
833
- <span class="cstat-no" title="statement not covered" > if (!this.isValidBcryptHash(hash)) {</span>
834
- <span class="cstat-no" title="statement not covered" > return true;</span>
835
- <span class="cstat-no" title="statement not covered" > }</span>
836
- <span class="cstat-no" title="statement not covered" ></span>
837
- <span class="cstat-no" title="statement not covered" > // Extract rounds from hash (format: $2b$XX$...)</span>
838
- <span class="cstat-no" title="statement not covered" > const match = hash.match(/^\$2[aby]\$(\d{2})\$/);</span>
839
- <span class="cstat-no" title="statement not covered" > if (!match) {</span>
840
- <span class="cstat-no" title="statement not covered" > return true;</span>
841
- <span class="cstat-no" title="statement not covered" > }</span>
842
- <span class="cstat-no" title="statement not covered" ></span>
843
- <span class="cstat-no" title="statement not covered" > const hashRounds = parseInt(match[1], 10);</span>
844
- <span class="cstat-no" title="statement not covered" > return hashRounds &lt; this.config.rounds;</span>
845
- <span class="cstat-no" title="statement not covered" > }</span>
846
- <span class="cstat-no" title="statement not covered" ></span>
847
- <span class="cstat-no" title="statement not covered" > /**</span>
848
- <span class="cstat-no" title="statement not covered" > * Validates bcrypt hash format.</span>
849
- <span class="cstat-no" title="statement not covered" > *</span>
850
- <span class="cstat-no" title="statement not covered" > * @param hash - The hash to validate</span>
851
- <span class="cstat-no" title="statement not covered" > * @returns True if valid bcrypt hash format</span>
852
- <span class="cstat-no" title="statement not covered" > */</span>
853
- <span class="cstat-no" title="statement not covered" > private isValidBcryptHash(hash: string): boolean {</span>
854
- <span class="cstat-no" title="statement not covered" > // bcrypt hash format: $2a$XX$22charsSalt31charsHash</span>
855
- <span class="cstat-no" title="statement not covered" > // Total length: 60 characters</span>
856
- <span class="cstat-no" title="statement not covered" > return /^\$2[aby]\$\d{2}\$[./A-Za-z0-9]{53}$/.test(hash);</span>
857
- <span class="cstat-no" title="statement not covered" > }</span>
858
- <span class="cstat-no" title="statement not covered" ></span>
859
- <span class="cstat-no" title="statement not covered" > /**</span>
860
- <span class="cstat-no" title="statement not covered" > * Returns current configuration (without sensitive defaults).</span>
861
- <span class="cstat-no" title="statement not covered" > */</span>
862
- <span class="cstat-no" title="statement not covered" > getConfig(): Readonly&lt;Omit&lt;Required&lt;PasswordHasherConfig&gt;, never&gt;&gt; {</span>
863
- <span class="cstat-no" title="statement not covered" > return { ...this.config };</span>
864
- <span class="cstat-no" title="statement not covered" > }</span>
865
- <span class="cstat-no" title="statement not covered" >}</span>
866
- <span class="cstat-no" title="statement not covered" ></span>
867
- <span class="cstat-no" title="statement not covered" >/**</span>
868
- <span class="cstat-no" title="statement not covered" > * Factory function to create a production-ready password hasher.</span>
869
- <span class="cstat-no" title="statement not covered" > *</span>
870
- <span class="cstat-no" title="statement not covered" > * @param rounds - Bcrypt rounds (default: 12)</span>
871
- <span class="cstat-no" title="statement not covered" > * @returns Configured PasswordHasher instance</span>
872
- <span class="cstat-no" title="statement not covered" > */</span>
873
- <span class="cstat-no" title="statement not covered" >export function createPasswordHasher(rounds = 12): PasswordHasher {</span>
874
- <span class="cstat-no" title="statement not covered" > return new PasswordHasher({ rounds });</span>
875
- <span class="cstat-no" title="statement not covered" >}</span>
876
- &nbsp;</pre></td></tr></table></pre>
877
-
878
- <div class='push'></div><!-- for sticky footer -->
879
- </div><!-- /wrapper -->
880
- <div class='footer quiet pad2 space-top1 center small'>
881
- Code coverage generated by
882
- <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
883
- at 2026-01-06T16:55:48.089Z
884
- </div>
885
- <script src="../prettify.js"></script>
886
- <script>
887
- window.onload = function () {
888
- prettyPrint();
889
- };
890
- </script>
891
- <script src="../sorter.js"></script>
892
- <script src="../block-navigation.js"></script>
893
- </body>
894
- </html>
895
-