@claude-flow/security 3.0.0-alpha.1

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 (133) hide show
  1. package/.agentic-flow/intelligence.json +16 -0
  2. package/README.md +234 -0
  3. package/__tests__/acceptance/security-compliance.test.ts +674 -0
  4. package/__tests__/coverage/base.css +224 -0
  5. package/__tests__/coverage/block-navigation.js +87 -0
  6. package/__tests__/coverage/coverage-final.json +11 -0
  7. package/__tests__/coverage/favicon.png +0 -0
  8. package/__tests__/coverage/index.html +161 -0
  9. package/__tests__/coverage/lcov-report/base.css +224 -0
  10. package/__tests__/coverage/lcov-report/block-navigation.js +87 -0
  11. package/__tests__/coverage/lcov-report/favicon.png +0 -0
  12. package/__tests__/coverage/lcov-report/index.html +161 -0
  13. package/__tests__/coverage/lcov-report/prettify.css +1 -0
  14. package/__tests__/coverage/lcov-report/prettify.js +2 -0
  15. package/__tests__/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  16. package/__tests__/coverage/lcov-report/sorter.js +210 -0
  17. package/__tests__/coverage/lcov-report/src/CVE-REMEDIATION.ts.html +838 -0
  18. package/__tests__/coverage/lcov-report/src/application/services/index.html +116 -0
  19. package/__tests__/coverage/lcov-report/src/application/services/security-application-service.ts.html +664 -0
  20. package/__tests__/coverage/lcov-report/src/credential-generator.ts.html +1189 -0
  21. package/__tests__/coverage/lcov-report/src/domain/entities/index.html +116 -0
  22. package/__tests__/coverage/lcov-report/src/domain/entities/security-context.ts.html +604 -0
  23. package/__tests__/coverage/lcov-report/src/domain/services/index.html +116 -0
  24. package/__tests__/coverage/lcov-report/src/domain/services/security-domain-service.ts.html +973 -0
  25. package/__tests__/coverage/lcov-report/src/index.html +206 -0
  26. package/__tests__/coverage/lcov-report/src/input-validator.ts.html +1483 -0
  27. package/__tests__/coverage/lcov-report/src/password-hasher.ts.html +895 -0
  28. package/__tests__/coverage/lcov-report/src/path-validator.ts.html +1660 -0
  29. package/__tests__/coverage/lcov-report/src/safe-executor.ts.html +1660 -0
  30. package/__tests__/coverage/lcov-report/src/token-generator.ts.html +1474 -0
  31. package/__tests__/coverage/lcov.info +3650 -0
  32. package/__tests__/coverage/prettify.css +1 -0
  33. package/__tests__/coverage/prettify.js +2 -0
  34. package/__tests__/coverage/sort-arrow-sprite.png +0 -0
  35. package/__tests__/coverage/sorter.js +210 -0
  36. package/__tests__/coverage/src/CVE-REMEDIATION.ts.html +838 -0
  37. package/__tests__/coverage/src/application/services/index.html +116 -0
  38. package/__tests__/coverage/src/application/services/security-application-service.ts.html +664 -0
  39. package/__tests__/coverage/src/credential-generator.ts.html +1189 -0
  40. package/__tests__/coverage/src/domain/entities/index.html +116 -0
  41. package/__tests__/coverage/src/domain/entities/security-context.ts.html +604 -0
  42. package/__tests__/coverage/src/domain/services/index.html +116 -0
  43. package/__tests__/coverage/src/domain/services/security-domain-service.ts.html +973 -0
  44. package/__tests__/coverage/src/index.html +206 -0
  45. package/__tests__/coverage/src/input-validator.ts.html +1483 -0
  46. package/__tests__/coverage/src/password-hasher.ts.html +895 -0
  47. package/__tests__/coverage/src/path-validator.ts.html +1660 -0
  48. package/__tests__/coverage/src/safe-executor.ts.html +1660 -0
  49. package/__tests__/coverage/src/token-generator.ts.html +1474 -0
  50. package/__tests__/credential-generator.test.ts +310 -0
  51. package/__tests__/fixtures/configurations.ts +419 -0
  52. package/__tests__/fixtures/index.ts +21 -0
  53. package/__tests__/helpers/create-mock.ts +469 -0
  54. package/__tests__/helpers/index.ts +32 -0
  55. package/__tests__/input-validator.test.ts +381 -0
  56. package/__tests__/integration/security-flow.test.ts +606 -0
  57. package/__tests__/password-hasher.test.ts +239 -0
  58. package/__tests__/path-validator.test.ts +302 -0
  59. package/__tests__/safe-executor.test.ts +292 -0
  60. package/__tests__/token-generator.test.ts +371 -0
  61. package/__tests__/unit/credential-generator.test.ts +182 -0
  62. package/__tests__/unit/password-hasher.test.ts +359 -0
  63. package/__tests__/unit/path-validator.test.ts +509 -0
  64. package/__tests__/unit/safe-executor.test.ts +667 -0
  65. package/__tests__/unit/token-generator.test.ts +310 -0
  66. package/dist/CVE-REMEDIATION.d.ts +86 -0
  67. package/dist/CVE-REMEDIATION.d.ts.map +1 -0
  68. package/dist/CVE-REMEDIATION.js +221 -0
  69. package/dist/CVE-REMEDIATION.js.map +1 -0
  70. package/dist/application/index.d.ts +7 -0
  71. package/dist/application/index.d.ts.map +1 -0
  72. package/dist/application/index.js +7 -0
  73. package/dist/application/index.js.map +1 -0
  74. package/dist/application/services/security-application-service.d.ts +71 -0
  75. package/dist/application/services/security-application-service.d.ts.map +1 -0
  76. package/dist/application/services/security-application-service.js +153 -0
  77. package/dist/application/services/security-application-service.js.map +1 -0
  78. package/dist/credential-generator.d.ts +176 -0
  79. package/dist/credential-generator.d.ts.map +1 -0
  80. package/dist/credential-generator.js +272 -0
  81. package/dist/credential-generator.js.map +1 -0
  82. package/dist/domain/entities/security-context.d.ts +68 -0
  83. package/dist/domain/entities/security-context.d.ts.map +1 -0
  84. package/dist/domain/entities/security-context.js +132 -0
  85. package/dist/domain/entities/security-context.js.map +1 -0
  86. package/dist/domain/index.d.ts +8 -0
  87. package/dist/domain/index.d.ts.map +1 -0
  88. package/dist/domain/index.js +8 -0
  89. package/dist/domain/index.js.map +1 -0
  90. package/dist/domain/services/security-domain-service.d.ts +71 -0
  91. package/dist/domain/services/security-domain-service.d.ts.map +1 -0
  92. package/dist/domain/services/security-domain-service.js +237 -0
  93. package/dist/domain/services/security-domain-service.js.map +1 -0
  94. package/dist/index.d.ts +119 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +145 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/input-validator.d.ts +306 -0
  99. package/dist/input-validator.d.ts.map +1 -0
  100. package/dist/input-validator.js +393 -0
  101. package/dist/input-validator.js.map +1 -0
  102. package/dist/password-hasher.d.ts +128 -0
  103. package/dist/password-hasher.d.ts.map +1 -0
  104. package/dist/password-hasher.js +183 -0
  105. package/dist/password-hasher.js.map +1 -0
  106. package/dist/path-validator.d.ts +148 -0
  107. package/dist/path-validator.d.ts.map +1 -0
  108. package/dist/path-validator.js +421 -0
  109. package/dist/path-validator.js.map +1 -0
  110. package/dist/safe-executor.d.ts +173 -0
  111. package/dist/safe-executor.d.ts.map +1 -0
  112. package/dist/safe-executor.js +370 -0
  113. package/dist/safe-executor.js.map +1 -0
  114. package/dist/token-generator.d.ts +224 -0
  115. package/dist/token-generator.d.ts.map +1 -0
  116. package/dist/token-generator.js +351 -0
  117. package/dist/token-generator.js.map +1 -0
  118. package/package.json +28 -0
  119. package/src/CVE-REMEDIATION.ts +251 -0
  120. package/src/application/index.ts +10 -0
  121. package/src/application/services/security-application-service.ts +193 -0
  122. package/src/credential-generator.ts +368 -0
  123. package/src/domain/entities/security-context.ts +173 -0
  124. package/src/domain/index.ts +17 -0
  125. package/src/domain/services/security-domain-service.ts +296 -0
  126. package/src/index.ts +271 -0
  127. package/src/input-validator.ts +466 -0
  128. package/src/password-hasher.ts +270 -0
  129. package/src/path-validator.ts +525 -0
  130. package/src/safe-executor.ts +525 -0
  131. package/src/token-generator.ts +463 -0
  132. package/tsconfig.json +9 -0
  133. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,895 @@
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.110Z
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
+