diff --git a/tests/test_downloads_tab_workflow_route.mjs b/tests/test_downloads_tab_workflow_route.mjs index bb2dcd5..ddcf2d7 100644 --- a/tests/test_downloads_tab_workflow_route.mjs +++ b/tests/test_downloads_tab_workflow_route.mjs @@ -19,6 +19,7 @@ import { } from '../web/resolver/node_context_menu.js'; import { startSplitterDrag } from '../web/resolver/utils/splitter_drag.js'; import { normalizeDownloadCategoryValue } from '../web/resolver/utils/category_utils.js'; +import { normalizeSha256 } from '../web/resolver/utils/hash_utils.js'; import { baseModelAliasMethods } from '../web/resolver/search/base_model_alias_methods.js'; import { searchHashMethods } from '../web/resolver/search/search_hash_methods.js'; import { missingModelStateMethods } from '../web/resolver/views/missing_model_state_methods.js'; @@ -34,6 +35,7 @@ import { } from '../web/resolver/custom_nodes/registry.js'; void normalizeDownloadCategoryValue; +void normalizeSha256; const projectRoot = path.resolve(import.meta.dirname, '..'); const queueMethodsSource = fs.readFileSync( diff --git a/tests/test_search_hash_methods.mjs b/tests/test_search_hash_methods.mjs index cdd8f2c..eb0a3d4 100644 --- a/tests/test_search_hash_methods.mjs +++ b/tests/test_search_hash_methods.mjs @@ -2,6 +2,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { searchHashMethods } from '../web/resolver/search/search_hash_methods.js'; +import { normalizeSha256 } from '../web/resolver/utils/hash_utils.js'; function createDialog(overrides = {}) { return { ...searchHashMethods, ...overrides }; @@ -10,6 +11,14 @@ function createDialog(overrides = {}) { const hashA = 'a'.repeat(64); const hashB = 'b'.repeat(64); +test('shared SHA-256 normalization preserves the accepted input contract', () => { + assert.equal(normalizeSha256(`sha256:${hashA.toUpperCase()}`), hashA); + assert.equal(normalizeSha256('SHA256=' + hashB), hashB); + assert.equal(normalizeSha256('short'), ''); + assert.equal(normalizeSha256(hashA + 'x'), ''); + assert.equal(normalizeSha256(null), ''); +}); + test('search hash normalization accepts SHA-256 prefixes and rejects invalid values', () => { const dialog = createDialog(); assert.equal(dialog.normalizeSearchResultSha256(`sha256:${hashA.toUpperCase()}`), hashA); diff --git a/web/resolver/search/search_hash_methods.js b/web/resolver/search/search_hash_methods.js index 3c6f529..bc4db1f 100644 --- a/web/resolver/search/search_hash_methods.js +++ b/web/resolver/search/search_hash_methods.js @@ -1,8 +1,8 @@ +import { normalizeSha256 } from '../utils/hash_utils.js'; + export const searchHashMethods = { normalizeSearchResultSha256(value = '') { - let text = String(value || '').trim(); - text = text.replace(/^sha256[:=]/i, '').trim().toLowerCase(); - return /^[a-f0-9]{64}$/.test(text) ? text : ''; + return normalizeSha256(value); }, getSearchResultSha256(result = {}) { diff --git a/web/resolver/utils/hash_utils.js b/web/resolver/utils/hash_utils.js new file mode 100644 index 0000000..71ad5e6 --- /dev/null +++ b/web/resolver/utils/hash_utils.js @@ -0,0 +1,5 @@ +export function normalizeSha256(value = '') { + let text = String(value || '').trim(); + text = text.replace(/^sha256[:=]/i, '').trim().toLowerCase(); + return /^[a-f0-9]{64}$/.test(text) ? text : ''; +} diff --git a/web/resolver/views/model_hash_compare_methods.js b/web/resolver/views/model_hash_compare_methods.js index cad85e9..a51e102 100644 --- a/web/resolver/views/model_hash_compare_methods.js +++ b/web/resolver/views/model_hash_compare_methods.js @@ -1,8 +1,8 @@ +import { normalizeSha256 } from '../utils/hash_utils.js'; + export const modelHashCompareMethods = { normalizeSha256ForCompare(value = '') { - let text = String(value || '').trim(); - text = text.replace(/^sha256[:=]/i, '').trim().toLowerCase(); - return /^[a-f0-9]{64}$/.test(text) ? text : ''; + return normalizeSha256(value); }, formatSha256Short(value = '') {