Skip to content

Merge hash service into a single file#3022

Open
JeethJJ wants to merge 1 commit into
thunder-id:mainfrom
JeethJJ:hash-service
Open

Merge hash service into a single file#3022
JeethJJ wants to merge 1 commit into
thunder-id:mainfrom
JeethJJ:hash-service

Conversation

@JeethJJ
Copy link
Copy Markdown
Contributor

@JeethJJ JeethJJ commented May 26, 2026

Purpose

The hash service is currently consist of unnecessary utils and models which can be combined into a single PR. Here we have merged all into a single hash.go and hash_test.go file.

Summary by CodeRabbit

  • Refactor

    • Consolidated cryptography into a unified crypto library; OTP thumbprinting, key management, JWKS/PKI thumbprints, and credential hashing/storage now use the new crypto APIs and updated credential data types.
  • Tests

    • Test suites adjusted to align with the unified crypto library and its hashing/thumbprint utilities.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d0483291-dcc5-4eee-b5aa-11f140b4dc35

📥 Commits

Reviewing files that changed from the base of the PR and between 496d6c4 and d74239d.

⛔ Files ignored due to path filters (1)
  • backend/tests/mocks/crypto/hashmock/HashServiceInterface_mock.go is excluded by !**/*_mock.go
📒 Files selected for processing (22)
  • backend/.mockery.public.yml
  • backend/cmd/server/servicemanager.go
  • backend/internal/entity/declarative_resource_test.go
  • backend/internal/entity/init.go
  • backend/internal/entity/model.go
  • backend/internal/entity/service.go
  • backend/internal/entity/service_test.go
  • backend/internal/notification/otp_service.go
  • backend/internal/notification/otp_service_test.go
  • backend/internal/oauth/jwks/service.go
  • backend/internal/system/cryptolib/hash.go
  • backend/internal/system/cryptolib/hash/init.go
  • backend/internal/system/cryptolib/hash/init_test.go
  • backend/internal/system/cryptolib/hash/model.go
  • backend/internal/system/cryptolib/hash/utils.go
  • backend/internal/system/cryptolib/hash/utils_test.go
  • backend/internal/system/cryptolib/hash_test.go
  • backend/internal/system/kmprovider/defaultkm/config_crypto_provider.go
  • backend/internal/system/kmprovider/defaultkm/pki/service.go
  • backend/internal/user/declarative_resource.go
  • backend/internal/user/declarative_resource_test.go
  • backend/internal/user/model.go
💤 Files with no reviewable changes (5)
  • backend/internal/system/cryptolib/hash/init.go
  • backend/internal/system/cryptolib/hash/utils_test.go
  • backend/internal/system/cryptolib/hash/utils.go
  • backend/internal/system/cryptolib/hash/init_test.go
  • backend/internal/system/cryptolib/hash/model.go
✅ Files skipped from review due to trivial changes (1)
  • backend/.mockery.public.yml
🚧 Files skipped from review as they are similar to previous changes (15)
  • backend/internal/system/kmprovider/defaultkm/config_crypto_provider.go
  • backend/internal/entity/service_test.go
  • backend/internal/entity/init.go
  • backend/internal/oauth/jwks/service.go
  • backend/internal/system/kmprovider/defaultkm/pki/service.go
  • backend/internal/notification/otp_service_test.go
  • backend/internal/user/model.go
  • backend/internal/notification/otp_service.go
  • backend/cmd/server/servicemanager.go
  • backend/internal/user/declarative_resource_test.go
  • backend/internal/user/declarative_resource.go
  • backend/internal/system/cryptolib/hash_test.go
  • backend/internal/entity/service.go
  • backend/internal/entity/declarative_resource_test.go
  • backend/internal/system/cryptolib/hash.go

📝 Walkthrough

Walkthrough

Consolidates hashing code from the former cryptolib/hash subpackage into top-level internal/system/cryptolib, exposing credential types, Initialize, and generic hash helpers; updates server init, domain models/services, user parsing, OTP/JWKS/KM providers, tests, and mock config to use the new package and types.

Changes

Cryptolib API Consolidation and Consumer Migration

Layer / File(s) Summary
Cryptolib core API consolidation
backend/internal/system/cryptolib/hash.go, backend/internal/system/cryptolib/hash_test.go
Introduce top-level cryptolib exports: credential/algorithm types, HashConfig, HashServiceInterface, Initialize, and generic hash utilities (GenerateThumbprint, GenerateThumbprintFromString, Hash, GetHash) and add tests for them.
Server initialization and config
backend/cmd/server/servicemanager.go, backend/.mockery.public.yml
buildHashConfig now returns cryptolib.HashConfig; registerServices calls cryptolib.Initialize(hashCfg); Mockery target package updated to internal/system/cryptolib.
Entity domain model and service migration
backend/internal/entity/model.go, backend/internal/entity/init.go, backend/internal/entity/service.go, backend/internal/entity/service_test.go, backend/internal/entity/declarative_resource_test.go
Entity StoredCredential fields and entityService use cryptolib types and cryptolib.HashServiceInterface; verification and stored params use cryptolib.CredParameters; tests updated.
User model and declarative resource migration
backend/internal/user/model.go, backend/internal/user/declarative_resource.go, backend/internal/user/declarative_resource_test.go
User Credential fields switch to cryptolib types; credential parsing initializes the hash service via cryptolib.Initialize and uses cryptolib.CredParameters; buildHashCfgForUser returns cryptolib.HashConfig.
Service thumbprint migration
backend/internal/notification/otp_service.go, backend/internal/notification/otp_service_test.go, backend/internal/oauth/jwks/service.go, backend/internal/system/kmprovider/defaultkm/config_crypto_provider.go, backend/internal/system/kmprovider/defaultkm/pki/service.go
Replace calls to hash.GenerateThumbprint* with cryptolib.GenerateThumbprint* for OTP values, JWKS x5tS256, and KM provider key IDs; update imports and tests accordingly.
Tests & removed legacy subpackage files
backend/internal/system/cryptolib/*
Old cryptolib/hash subpackage pieces were consolidated into the top-level cryptolib package and tests adjusted to the new package and helpers.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • darshanasbg
  • ThaminduDilshan
  • thiva-k
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is minimal but addresses the core purpose. However, it lacks detailed sections such as Approach, Related Issues/PRs, Checklist, and Security checks that are specified in the template. Expand the description to include the Approach section explaining the consolidation strategy, and ensure all template sections (Checklist, Security checks, Related Issues/PRs) are addressed.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Merge hash service into a single file' clearly and accurately describes the main objective of this PR—consolidating hash-related code from multiple files into single hash.go and hash_test.go files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@JeethJJ JeethJJ marked this pull request as ready for review May 27, 2026 04:50
@JeethJJ JeethJJ force-pushed the hash-service branch 2 times, most recently from dbdc4d6 to c4aa39a Compare May 27, 2026 04:51
@JeethJJ JeethJJ added Type/Improvement skip-changelog Skip generating changelog for a particular PR labels May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/internal/entity/service.go (1)

529-536: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve full hash parameters during store/verify.

Line 532 and Line 927 only copy Salt, Iterations, and KeySize. Memory and Parallelism are dropped, which can make Argon2 credentials fail verification.

💡 Suggested fix
 			ref := cryptolib.Credential{
 				Algorithm: stored.StorageAlgo,
 				Hash:      stored.Value,
 				Parameters: cryptolib.CredParameters{
 					Salt:       stored.StorageAlgoParams.Salt,
 					Iterations: stored.StorageAlgoParams.Iterations,
+					Memory:     stored.StorageAlgoParams.Memory,
+					Parallelism: stored.StorageAlgoParams.Parallelism,
 					KeySize:    stored.StorageAlgoParams.KeySize,
 				},
 			}
@@
 					StorageAlgo: credHash.Algorithm,
 					StorageAlgoParams: cryptolib.CredParameters{
 						Salt:       credHash.Parameters.Salt,
 						Iterations: credHash.Parameters.Iterations,
+						Memory:     credHash.Parameters.Memory,
+						Parallelism: credHash.Parameters.Parallelism,
 						KeySize:    credHash.Parameters.KeySize,
 					},
 					Value: credHash.Hash,

Also applies to: 927-931

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/entity/service.go` around lines 529 - 536, The cryptographic
parameter mapping drops Argon2-specific fields causing verification failures:
when building cryptolib.Credential/CredParameters (the code that sets ref :=
cryptolib.Credential and the other occurrence around the
stored.StorageAlgoParams usage), include all fields from
stored.StorageAlgoParams — add Memory and Parallelism into the CredParameters
construction in the same places where Salt, Iterations, and KeySize are set so
Argon2 parameters are preserved for store/verify.
backend/internal/user/declarative_resource.go (1)

453-455: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep Argon2 pre-hashed params intact when parsing YAML.

Line 453-Line 455 only read iterations, keySize, and salt. memory and parallelism are dropped for pre-hashed credentials.

💡 Suggested fix
 	iterations, _ := paramsMap["iterations"].(int)
+	memory, _ := paramsMap["memory"].(int)
+	parallelism, _ := paramsMap["parallelism"].(int)
 	keySize, _ := paramsMap["keySize"].(int)
 	salt, _ := paramsMap["salt"].(string)

 	return Credential{
 		StorageType: storageType,
 		StorageAlgo: cryptolib.CredAlgorithm(storageAlgo),
 		StorageAlgoParams: cryptolib.CredParameters{
 			Iterations: iterations,
+			Memory:     memory,
+			Parallelism: parallelism,
 			KeySize:    keySize,
 			Salt:       salt,
 		},
 		Value: value,
 	}, nil

Also applies to: 460-464

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/user/declarative_resource.go` around lines 453 - 455, The
YAML parsing currently extracts only iterations, keySize, and salt from
paramsMap (variables named iterations, keySize, salt), which drops Argon2's
memory and parallelism fields; update the parsing to also read and preserve
memory and parallelism from paramsMap (e.g., memory, parallelism) with the same
type assertions used for the other fields, and make the same change in the other
parsing block referenced (the block at lines ~460-464) so pre-hashed Argon2
params remain intact when unmarshalling.
🧹 Nitpick comments (2)
backend/internal/system/cryptolib/hash_test.go (2)

1164-1175: ⚡ Quick win

Remove the unused runtime-config bootstrap from this test.

Initialize only uses the HashConfig passed in, so this setup does not affect the assertion and just adds global-state coupling to a unit test.

Proposed cleanup
 func (suite *InitTestSuite) TestInitialize() {
-	testConfig := &config.Config{
-		Crypto: config.CryptoConfig{
-			PasswordHashing: config.PasswordHashingConfig{
-				Algorithm: string(SHA256),
-				SHA256: config.SHA256Config{
-					SaltSize: 32,
-				},
-			},
-		},
-	}
-	config.ResetServerRuntime()
-	_ = config.InitializeServerRuntime("/test/thunderid/home", testConfig)
-
 	service, err := Initialize(HashConfig{
 		Algorithm: SHA256,
 		SaltSize:  32,
 	})

As per coding guidelines, **/*.{go,js,ts,tsx}: Delete dead code cleanly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/system/cryptolib/hash_test.go` around lines 1164 - 1175, The
test includes an unnecessary global runtime bootstrap: remove the calls to
config.ResetServerRuntime() and
config.InitializeServerRuntime("/test/thunderid/home", testConfig) (and any
related runtime setup) because Initialize only uses the local HashConfig passed
via testConfig; keep the testConfig definition and use it directly with the
hashing Initialize function, eliminating the global-state coupling introduced by
ResetServerRuntime and InitializeServerRuntime.

1247-1290: ⚡ Quick win

Assert algorithm-specific outputs here.

Hash returning the wrong algorithm for one or more enums would still pass these tests, and GetHash only proves that some hash was returned. Please check known digests or at least the expected output sizes (32, 48, 64) so the new mapping logic is actually covered.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/system/cryptolib/hash_test.go` around lines 1247 - 1290, The
tests currently only check that Hash and GetHash return non-empty values; update
TestHash and TestGetHash to assert algorithm-specific outputs by verifying the
returned digest lengths and at least one known digest: for Hash(data,
GenericSHA256) assert len(hashed) == 32 (and optionally compare to the known
SHA-256 digest of "hello world"), for GenericSHA384 assert len == 48, and for
GenericSHA512 assert len == 64; likewise in TestGetHash, after obtaining h from
GetHash(tc.alg) either compute h.Sum(nil) or use h to hash known input and
assert output sizes (32/48/64) and optionally compare one known digest to ensure
the mapping logic in Hash, GetHash, and HashAlgorithm (including
GenericSHA256/GenericSHA384/GenericSHA512) is correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/internal/system/cryptolib/hash.go`:
- Around line 335-343: The GenerateThumbprint and GenerateThumbprintFromString
helpers currently use base64.StdEncoding which produces '+' '/' and '=' padding;
change them to use base64.RawURLEncoding (or base64.URLEncoding without padding)
so the SHA-256 thumbprint is encoded as base64url with no padding (e.g., replace
base64.StdEncoding.EncodeToString(h[:]) with
base64.RawURLEncoding.EncodeToString(h[:]) and ensure
GenerateThumbprintFromString still delegates to GenerateThumbprint).

---

Outside diff comments:
In `@backend/internal/entity/service.go`:
- Around line 529-536: The cryptographic parameter mapping drops Argon2-specific
fields causing verification failures: when building
cryptolib.Credential/CredParameters (the code that sets ref :=
cryptolib.Credential and the other occurrence around the
stored.StorageAlgoParams usage), include all fields from
stored.StorageAlgoParams — add Memory and Parallelism into the CredParameters
construction in the same places where Salt, Iterations, and KeySize are set so
Argon2 parameters are preserved for store/verify.

In `@backend/internal/user/declarative_resource.go`:
- Around line 453-455: The YAML parsing currently extracts only iterations,
keySize, and salt from paramsMap (variables named iterations, keySize, salt),
which drops Argon2's memory and parallelism fields; update the parsing to also
read and preserve memory and parallelism from paramsMap (e.g., memory,
parallelism) with the same type assertions used for the other fields, and make
the same change in the other parsing block referenced (the block at lines
~460-464) so pre-hashed Argon2 params remain intact when unmarshalling.

---

Nitpick comments:
In `@backend/internal/system/cryptolib/hash_test.go`:
- Around line 1164-1175: The test includes an unnecessary global runtime
bootstrap: remove the calls to config.ResetServerRuntime() and
config.InitializeServerRuntime("/test/thunderid/home", testConfig) (and any
related runtime setup) because Initialize only uses the local HashConfig passed
via testConfig; keep the testConfig definition and use it directly with the
hashing Initialize function, eliminating the global-state coupling introduced by
ResetServerRuntime and InitializeServerRuntime.
- Around line 1247-1290: The tests currently only check that Hash and GetHash
return non-empty values; update TestHash and TestGetHash to assert
algorithm-specific outputs by verifying the returned digest lengths and at least
one known digest: for Hash(data, GenericSHA256) assert len(hashed) == 32 (and
optionally compare to the known SHA-256 digest of "hello world"), for
GenericSHA384 assert len == 48, and for GenericSHA512 assert len == 64; likewise
in TestGetHash, after obtaining h from GetHash(tc.alg) either compute h.Sum(nil)
or use h to hash known input and assert output sizes (32/48/64) and optionally
compare one known digest to ensure the mapping logic in Hash, GetHash, and
HashAlgorithm (including GenericSHA256/GenericSHA384/GenericSHA512) is correct.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 858f69e1-0819-4b5e-8908-cd88b65bc7d8

📥 Commits

Reviewing files that changed from the base of the PR and between 24d4d00 and c4aa39a.

⛔ Files ignored due to path filters (1)
  • backend/tests/mocks/crypto/hashmock/HashServiceInterface_mock.go is excluded by !**/*_mock.go
📒 Files selected for processing (22)
  • backend/.mockery.public.yml
  • backend/cmd/server/servicemanager.go
  • backend/internal/entity/declarative_resource_test.go
  • backend/internal/entity/init.go
  • backend/internal/entity/model.go
  • backend/internal/entity/service.go
  • backend/internal/entity/service_test.go
  • backend/internal/notification/otp_service.go
  • backend/internal/notification/otp_service_test.go
  • backend/internal/oauth/jwks/service.go
  • backend/internal/system/cryptolib/hash.go
  • backend/internal/system/cryptolib/hash/init.go
  • backend/internal/system/cryptolib/hash/init_test.go
  • backend/internal/system/cryptolib/hash/model.go
  • backend/internal/system/cryptolib/hash/utils.go
  • backend/internal/system/cryptolib/hash/utils_test.go
  • backend/internal/system/cryptolib/hash_test.go
  • backend/internal/system/kmprovider/defaultkm/config_crypto_provider.go
  • backend/internal/system/kmprovider/defaultkm/pki/service.go
  • backend/internal/user/declarative_resource.go
  • backend/internal/user/declarative_resource_test.go
  • backend/internal/user/model.go
💤 Files with no reviewable changes (5)
  • backend/internal/system/cryptolib/hash/init.go
  • backend/internal/system/cryptolib/hash/model.go
  • backend/internal/system/cryptolib/hash/utils.go
  • backend/internal/system/cryptolib/hash/init_test.go
  • backend/internal/system/cryptolib/hash/utils_test.go

Comment on lines +335 to +343
// GenerateThumbprint generates a SHA-256 thumbprint for the given data.
func GenerateThumbprint(data []byte) string {
h := sha256.Sum256(data)
return base64.StdEncoding.EncodeToString(h[:])
}

// GenerateThumbprintFromString generates a SHA-256 thumbprint for the given string data.
func GenerateThumbprintFromString(data string) string {
return GenerateThumbprint([]byte(data))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use base64url, not standard Base64, for thumbprints.

StdEncoding emits +, /, and = padding, but the downstream JWKS x5t#S256 path needs base64url without padding. As written, this helper will generate non-compliant thumbprints for that contract.

Proposed fix
 func GenerateThumbprint(data []byte) string {
 	h := sha256.Sum256(data)
-	return base64.StdEncoding.EncodeToString(h[:])
+	return base64.RawURLEncoding.EncodeToString(h[:])
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// GenerateThumbprint generates a SHA-256 thumbprint for the given data.
func GenerateThumbprint(data []byte) string {
h := sha256.Sum256(data)
return base64.StdEncoding.EncodeToString(h[:])
}
// GenerateThumbprintFromString generates a SHA-256 thumbprint for the given string data.
func GenerateThumbprintFromString(data string) string {
return GenerateThumbprint([]byte(data))
// GenerateThumbprint generates a SHA-256 thumbprint for the given data.
func GenerateThumbprint(data []byte) string {
h := sha256.Sum256(data)
return base64.RawURLEncoding.EncodeToString(h[:])
}
// GenerateThumbprintFromString generates a SHA-256 thumbprint for the given string data.
func GenerateThumbprintFromString(data string) string {
return GenerateThumbprint([]byte(data))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/system/cryptolib/hash.go` around lines 335 - 343, The
GenerateThumbprint and GenerateThumbprintFromString helpers currently use
base64.StdEncoding which produces '+' '/' and '=' padding; change them to use
base64.RawURLEncoding (or base64.URLEncoding without padding) so the SHA-256
thumbprint is encoded as base64url with no padding (e.g., replace
base64.StdEncoding.EncodeToString(h[:]) with
base64.RawURLEncoding.EncodeToString(h[:]) and ensure
GenerateThumbprintFromString still delegates to GenerateThumbprint).

@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

❌ Patch coverage is 88.88889% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
backend/cmd/server/servicemanager.go 50.00% 5 Missing ⚠️
backend/internal/user/declarative_resource.go 86.66% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@JeethJJ JeethJJ enabled auto-merge May 27, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Skip generating changelog for a particular PR Type/Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants