2626 </span >
2727 </p >
2828 <p class =" control is-expanded" >
29- <input v-if =" searchTypeBoolean" v-model.trim =" queryString" @keyup.enter = " onKeyUpEnter "
30- @keyup = " validateQueryString " type =" text" class =" input cve-id-input 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"
3131 placeholder =" Enter keywords (e.g.: CVE ID, sql injection, etc.)" />
32- <input v-else v-model.trim =" cveId" @keyup.enter = " onKeyUpEnter " @keyup = " validateQueryString "
32+ <input v-else v-model.trim =" cveId" @keyup = " onKeyUp " @keyup.enter = " validate "
3333 type =" text" class =" input cve-id-input" placeholder =" Enter CVE ID (CVE-YYYY-NNNN)" />
3434 </p >
3535 <p class =" control" >
3636 <button @click =" validate" class =" button cve-button cve-button-accent-warm"
37- :class =" { 'is-loading': cveListSearchStore.isSearching, 'disabled': cveListSearchStore.isSeachButtonDisabled }"
38- :aria-disabled =" cveListSearchStore.isSeachButtonDisabled" >
37+ :class =" { 'is-loading': cveListSearchStore.isSearching, 'disabled': cveListSearchStore.isSearchButtonDisabled }"
38+ :aria-disabled =" cveListSearchStore.isSearchButtonDisabled"
39+ :disabled =" cveListSearchStore.isSearchButtonDisabled" >
3940 {{ searchTypeBoolean ? 'Search' : 'Find'}}
4041 </button >
4142 </p >
@@ -61,10 +62,16 @@ import { useRoute, useRouter } from 'vue-router';
6162import { usecveRecordStore } from ' @/stores/cveRecord' ;
6263import { useGenericGlobalsStore } from ' @/stores/genericGlobals' ;
6364
65+ const cveIdRegex = / ^ CVE\p {Pd}(?<year>\d {4} )\p {Pd}(?<id>\d {4,} )$ / iu ;
66+ const wordRegex = / ^ [a-z0-9 ] + $ / i ;
67+
68+ const cveStartYear = 1999 ;
69+
6470let cveListSearchStore = useCveListSearchStore ();
6571const route = useRoute ();
6672const router = useRouter ();
6773
74+ let prevSearchValue = ref (' ' );
6875let queryString = ref (' ' );
6976let errorMessage = ref (' ' );
7077
@@ -86,12 +93,9 @@ watch(searchType, () => {
8693watch (
8794 () => route .query ,
8895 () => {
89- if (route .query ? .query ) {
90- queryString .value = route .query .query .trim ();
91- validate ();
92- } else {
93- queryString .value = cveListSearchStore .query = ' ' ;
94- errorMessage .value = ' ' ;
96+ if (searchTypeBoolean .value && route .query ? .query ) {
97+ queryString .value = route .query .query .trim ();
98+ validate ();
9599 }
96100 }
97101)
@@ -100,9 +104,19 @@ function resetStates() {
100104 cveListSearchStore .searchType = cveGenericGlobalsStore .useSearch = searchTypeBoolean .value ;
101105 cveId = ' ' ;
102106 queryString .value = cveListSearchStore .query = ' ' ;
103- errorMessage .value = ' ' ;
104- cveListSearchStore .showHelpText = false ;
105- cveListSearchStore .isSeachButtonDisabled = true ;
107+ showHelpMessage (' ' );
108+ cveListSearchStore .isSearchButtonDisabled = true ;
109+ }
110+
111+ function showHelpMessage (helpText ) {
112+
113+ if (helpText .length ) {
114+ errorMessage .value = helpText;
115+ cveListSearchStore .showHelpText = true ;
116+ } else {
117+ errorMessage .value = ' ' ;
118+ cveListSearchStore .showHelpText = false ;
119+ }
106120}
107121
108122function startSearch () {
@@ -116,15 +130,15 @@ function startSearch() {
116130 cveGenericGlobalsStore.setCurrentServicesUrl(cveGenericGlobalsStore.cveServiceTestBaseUrl)
117131 }
118132 if (cveGenericGlobalsStore.useSearch) {
119- if (queryString.value !== cveListSearchStore.query) {
120133 cveListSearchStore.$reset();
121134 cveListSearchStore.query = queryString.value;
122- router.push({
123- name: 'SearchResults',
124- query: { query: cveListSearchStore.query }
125- });
126- cveListSearchStore.search();
127- }
135+ if (route.name != 'SearchResults' || !route.query?.query
136+ || (route.query.query != cveListSearchStore.query)) {
137+
138+ router.push({name: 'SearchResults',
139+ query: {query: cveListSearchStore.query}});
140+ } else
141+ cveListSearchStore.search();
128142 } else {
129143 const lookupPath = ` /CVERecord?id=${cveId }` ;
130144
@@ -133,51 +147,83 @@ function startSearch() {
133147}
134148
135149function validateQueryString() {
136- if (searchTypeBoolean.value) {
137- const alphaNumericDashPattern = new RegExp(/^[a-zA-Z0-9 ]+$/, 'i').test(queryString.value);
138- const cveIdPattern = new RegExp(/^CVE-\d {4}-\d {4,7}$/, 'i').test(queryString.value);
139-
140- if (queryString.value.length > 0 && !alphaNumericDashPattern && !cveIdPattern) {
141- cveListSearchStore.isSeachButtonDisabled = true;
142- errorMessage.value = 'Only letters, numbers, and CVE IDs (CVE-YYYY-NNNN) are allowed.';
143- cveListSearchStore.showHelpText = true;
144- } else if (queryString.value.length === 0) {
145- cveListSearchStore.isSeachButtonDisabled = true;
146- errorMessage.value = '';
147- cveListSearchStore.showHelpText = false;
150+
151+ const contentMessage = 'Enter words of alphanumeric characters OR a single CVD ID (CVE-YYYY-NNNN).';
152+ const isSearch = searchTypeBoolean.value;
153+ const searchValue = isSearch ? queryString.value : cveId;
154+
155+ prevSearchValue.value = searchValue;
156+ cveListSearchStore.isSearchButtonDisabled = true;
157+ showHelpMessage('');
158+
159+ if (!searchValue)
160+ return !cveListSearchStore.isSearchButtonDisabled;
161+
162+ const cveIdMatch = cveIdRegex.exec(searchValue)
163+
164+ if (cveIdMatch) {
165+ const year = parseInt(cveIdMatch.groups.year);
166+ const id = cveIdMatch.groups.id;
167+ const currentYear = new Date().getFullYear();
168+
169+ if (cveStartYear <= year && year <= currentYear) {
170+ const normalizedCveId = ` CVE-${year }-${id }` ;
171+ if (isSearch)
172+ queryString.value = normalizedCveId;
173+ else
174+ cveId = normalizedCveId;
148175 } else {
149- cveListSearchStore.isSeachButtonDisabled = false;
150- errorMessage.value = '';
151- cveListSearchStore.showHelpText = false;
176+ showHelpMessage(` CVE ID year must be within ${cveStartYear }-${currentYear }` );
152177 }
153- } else {
154- //Basic Checking
155- const cveIdPattern = new RegExp(/^CVE-\d {4}-\d {4,7}$/, 'i').test(cveId);
156- if (cveId.length > 0 && !cveIdPattern) {
157- cveListSearchStore.isSeachButtonDisabled = true;
158- errorMessage.value = 'Required CVE ID format: CVE-YYYY-NNNN';
159- cveListSearchStore.showHelpText = true;
160- } else if (cveId.length === 0) {
161- cveListSearchStore.isSeachButtonDisabled = true;
162- errorMessage.value = '';
163- cveListSearchStore.showHelpText = false;
164- } else {
165- cveListSearchStore.isSeachButtonDisabled = false;
166- errorMessage.value = '';
167- cveListSearchStore.showHelpText = false;
178+ }
179+
180+ if (isSearch) {
181+
182+ // Search: if the query string isn't a CVE ID and it doesn't just consist
183+ // of "typical" words (alphanumeric phrases), then it's an error.
184+
185+ if (!cveIdMatch && !wordRegex.test(searchValue)) {
186+ showHelpMessage(contentMessage);
187+ } else if (!errorMessage.value) {
188+
189+ // The provided search string is good.
190+ cveListSearchStore.isSearchButtonDisabled = false;
168191 }
192+ } else if (cveIdMatch) {
193+
194+ // Legacy Find by CVE ID and it's in the correct format.
195+ cveListSearchStore.isSearchButtonDisabled = false;
196+
197+ } else if (!errorMessage.value) {
198+
199+ // Legacy Find by CVE ID but the query string is not a CVE ID.
200+ showHelpMessage('Required CVE ID format: CVE-YYYY-NNNN');
169201 }
202+
203+ return !cveListSearchStore.isSearchButtonDisabled;
170204}
171205
172- function onKeyUpEnter() {
173- validate()
206+ function onKeyUp() {
207+ if (cveListSearchStore.isSearchButtonDisabled) {
208+ const isSearch = searchTypeBoolean.value;
209+ const searchValue = isSearch ? queryString.value : cveId;
210+
211+ if (prevSearchValue.value !== searchValue)
212+ cveListSearchStore.isSearchButtonDisabled = false;
213+ }
174214}
175215
176216function validate() {
177217
178- validateQueryString();
179- if (!cveListSearchStore.isSeachButtonDisabled) {
180- startSearch();
218+ if (validateQueryString()) {
219+ try {
220+ cveListSearchStore.isSearchButtonDisabled = true;
221+ startSearch();
222+ } finally {
223+ cveListSearchStore.isSearchButtonDisabled = false;
224+ }
225+ } else if (route.name != 'home' || route?.query) {
226+ router.push({name: 'home', query: {}});
181227 }
182228}
183229
@@ -189,8 +235,8 @@ const websiteEnv = computed(() => {
189235<style scoped lang="scss">
190236.disabled {
191237 opacity: 0.7 !important;
192- background-color: #3d4551;
193- color: white;
238+ background-color: #3d4551 !important ;
239+ color: white !important ;
194240 border-color: #dbdbdb;
195241 box-shadow: none;
196242}
@@ -216,4 +262,4 @@ const websiteEnv = computed(() => {
216262 cursor: pointer;
217263 text-decoration: none !important;
218264}
219- </style>
265+ </style>
0 commit comments