1919 <div class =" field has-addons mt-1" >
2020 <p class =" control" >
2121 <span v-if =" websiteEnv !== 'prd'" class =" select cve-search-selector" >
22- <select v-model =" searchType" >
22+ <select v-model =" searchType" @input = " searchTypeSwap " >
2323 <option >Search CVE List</option >
2424 <option >Find a Test CVE Record/ID (Legacy)</option >
2525 </select >
2626 </span >
2727 </p >
2828 <p class =" control is-expanded" >
29- <input v-if =" searchTypeBoolean" v-model.trim =" queryString" @keyup = " onKeyUp "
30- @keyup.enter =" validate" type =" text" class =" input cve-id-input is-expanded"
29+ <input v-if =" searchTypeBoolean" v-model.trim =" queryString"
30+ @input = " onInputChange " @ keyup.enter =" validate" type =" text" class =" input cve-id-input is-expanded"
3131 placeholder =" Enter keywords (e.g.: CVE ID, sql injection, etc.)" />
32- <input v-else v-model.trim =" cveId" @keyup = " onKeyUp " @keyup.enter =" validate"
32+ <input v-else v-model.trim =" cveId" @input = " onInputChange " @keyup.enter =" validate"
3333 type =" text" class =" input cve-id-input" placeholder =" Enter CVE ID (CVE-YYYY-NNNN)" />
3434 </p >
3535 <p class =" control" >
@@ -65,7 +65,11 @@ import { useGenericGlobalsStore } from '@/stores/genericGlobals';
6565const cveIdRegex = / ^ CVE\p {Pd}(?<year>\d {4} )\p {Pd}(?<id>\d {4,} )$ / iu ;
6666const wordRegex = / ^ [a-z0-9 ] + $ / i ;
6767
68- const cveStartYear = 1999 ;
68+ // This is the current maximum supported length of the "suffix" portion of
69+ // the CVE ID. The schema defines a suffix length up to 19, but code in
70+ // other modules only supports what's defined here.
71+
72+ const maxCveIdSuffix = 7 ;
6973
7074let cveListSearchStore = useCveListSearchStore ();
7175const route = useRoute ();
@@ -80,8 +84,9 @@ let cveRecordStore = usecveRecordStore();
8084let searchType = ref (' Search CVE List' );
8185let cveId = cveRecordStore .cveId ;
8286
83- // this seems redundant, but it fixes an edge case.
84- // if a user searches for a particular field, then on the results page flips the toggle, THEN refreshes without searching, this will keep the correct helper text showing.
87+ // this seems redundant, but it fixes an edge case. if a user searches for a
88+ // particular field, then on the results page flips the toggle, THEN refreshes
89+ // without searching, this will keep the correct helper text showing.
8590let searchTypeBoolean = computed (() => {
8691 return searchType .value == ' Search CVE List' ? true : false ;
8792});
@@ -120,7 +125,8 @@ function showHelpMessage(helpText) {
120125}
121126
122127function startSearch () {
123- // We only want to flip the search item _When we actually do a search_ otherwise we should default back to what we were on a page refresh
128+ // We only want to flip the search item _When we actually do a search_
129+ // otherwise we should default back to what we were on a page refresh
124130 if (searchTypeBoolean .value ) {
125131 cveGenericGlobalsStore .setUseSearch (true );
126132 cveGenericGlobalsStore .setCurrentServicesUrl (` https://${ import .meta.env.VITE_CVE_SERVICES_BASE_URL}` )
@@ -132,8 +138,8 @@ function startSearch() {
132138 if (cveGenericGlobalsStore.useSearch) {
133139 cveListSearchStore.$reset();
134140 cveListSearchStore.query = queryString.value;
135- if (route.name != 'SearchResults' || !route.query?.query
136- || (route.query.query != cveListSearchStore.query)) {
141+ if (route? .name != = 'SearchResults' || !route.query?.query
142+ || (route.query.query !== cveListSearchStore.query)) {
137143
138144 router.push({name: 'SearchResults',
139145 query: {query: cveListSearchStore.query}});
@@ -148,32 +154,39 @@ function startSearch() {
148154
149155function validateQueryString() {
150156
151- const contentMessage = 'Enter words of alphanumeric characters OR a single CVD ID (CVE-YYYY-NNNN).';
157+ const contentMessage = 'Enter words of alphanumeric characters OR a single CVE ID (CVE-YYYY-NNNN).';
152158 const isSearch = searchTypeBoolean.value;
153159 const searchValue = isSearch ? queryString.value : cveId;
154160
161+ // The previous search value is only used in determining whether to enable
162+ // the search (see its usage in onInputChange() below).
163+
155164 prevSearchValue.value = searchValue;
156165 cveListSearchStore.isSearchButtonDisabled = true;
157166 showHelpMessage('');
158167
159168 if (!searchValue)
160169 return !cveListSearchStore.isSearchButtonDisabled;
161170
162- const cveIdMatch = cveIdRegex.exec(searchValue)
171+ const cveIdMatch = cveIdRegex.exec(searchValue);
172+ let cveIdValid = false;
163173
164174 if (cveIdMatch) {
165- const year = parseInt(cveIdMatch.groups.year);
175+ // The search string is a CVE ID. Re-assemble the components, making sure
176+ // "normal" dashes are used to separate the components.
177+
178+ const year = cveIdMatch.groups.year;
166179 const id = cveIdMatch.groups.id;
167- const currentYear = new Date().getFullYear() ;
180+ const normalizedCveId = ` CVE-${ year }-${ id } ` ;
168181
169- if (cveStartYear <= year && year <= currentYear ) {
170- const normalizedCveId = ` CVE-${ year }-${ id } ` ;
182+ if (id.length <= maxCveIdSuffix ) {
183+ cveIdValid = true ;
171184 if (isSearch)
172185 queryString.value = normalizedCveId;
173186 else
174187 cveId = normalizedCveId;
175188 } else {
176- showHelpMessage(` CVE ID year must be within ${ cveStartYear }-${ currentYear } ` );
189+ showHelpMessage(` Invalid CVE ID " ${normalizedCveId} " - identifier out of range ` );
177190 }
178191 }
179192
@@ -189,7 +202,7 @@ function validateQueryString() {
189202 // The provided search string is good.
190203 cveListSearchStore.isSearchButtonDisabled = false;
191204 }
192- } else if (cveIdMatch ) {
205+ } else if (cveIdValid ) {
193206
194207 // Legacy Find by CVE ID and it's in the correct format.
195208 cveListSearchStore.isSearchButtonDisabled = false;
@@ -203,17 +216,38 @@ function validateQueryString() {
203216 return !cveListSearchStore.isSearchButtonDisabled;
204217}
205218
206- function onKeyUp() {
207- if (cveListSearchStore.isSearchButtonDisabled) {
219+ function onInputChange() {
220+ // This function is called when the search string changes. The only purpose
221+ // is to clear the way for the search if there's a value (it's not empty)
222+ // and it's not the same as a "bad" value used in the previous search.
223+ // As long as this is the case, we enable the search, which will then check
224+ // the validity of the search string when initiated.
225+
208226 const isSearch = searchTypeBoolean.value;
209227 const searchValue = isSearch ? queryString.value : cveId;
210228
229+ if (cveListSearchStore.isSearchButtonDisabled) {
211230 if (prevSearchValue.value !== searchValue)
212231 cveListSearchStore.isSearchButtonDisabled = false;
232+ } else if (!searchValue.length) {
233+ // This handles the case when the user clears the input field following
234+ // a successful search, possibly by using the delete button or selecting
235+ // the input and cutting via the keyboard. It makes the state consistent
236+ // with when the page starts with nothing in the input field.
237+
238+ cveListSearchStore.isSearchButtonDisabled = true;
213239 }
214240}
215241
216242function validate() {
243+ // This function is called when initiating a search. It's invoked as a result
244+ // of one of these user actions:
245+ //
246+ // - pressing enter in the input field.
247+ // - clicking the Search/Find button.
248+ // - entering the search URL.
249+ //
250+ // Provided the search string is valid, the search is started.
217251
218252 if (validateQueryString()) {
219253 try {
@@ -222,11 +256,31 @@ function validate() {
222256 } finally {
223257 cveListSearchStore.isSearchButtonDisabled = false;
224258 }
225- } else if (route.name != 'home' || route?.query) {
259+ } else if (route?.name != 'home' || route?.query) {
260+ // The query string is not valid and the route indicates that the URL
261+ // is most likely associated with a previous valid search. The user
262+ // has initiated another search that is unrelated to the URL being
263+ // displayed (e.g., cve.org/CVERecord/SearchResults?query=CVE-2020-0001).
264+ // Rather than display a URL that is not associated with the
265+ // current search, reset it to the home route.
266+
226267 router.push({name: 'home', query: {}});
227268 }
228269}
229270
271+ function searchTypeSwap() {
272+
273+ // This function is used only when there's an option menu present that
274+ // allows for using the "legacy" find, which does NOT apply to the
275+ // production website. When a switch is made in the type of search, this
276+ // function resets the previous search value and removes the URL that's
277+ // applicable to the other search type.
278+
279+ prevSearchValue.value = '';
280+
281+ router.push({name: 'home', query: {}});
282+ }
283+
230284const websiteEnv = computed(() => {
231285 return import.meta.env.VITE_WEBSITE_ENVIRONMENT;
232286});
0 commit comments