-
Notifications
You must be signed in to change notification settings - Fork 27
Refactor NIP-44 key derivation and improve error handling #501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
fb32af9
fix(nip44): use HKDF instead of PBKDF2 for key derivation
12f4cb1
chore(release): bump version to 1.2.0
5a3c903
fix(nip44): use proper HKDF-Extract for conversation key
de36c4d
docs: enhance coding guidelines with detailed principles and best pra…
64c186e
fix(Kind): improve error handling for unknown kind values
e3cb5a0
fix(ws): refactor response handling to use CompletableFuture for even…
2a53b78
chore(release): bump version to 1.2.1
4167c64
chore(docs): update PR template with standardized sections and guidel…
9a3ace0
fix(Kind): add safer Optional-based lookup and strict validation methods
737bee1
test(Kind): expand unit tests for improved validation coverage
88049cb
test(ws): enhance NIP-60 filter JSON serialization tests for improved…
adbee1d
fix(ws): introduce PendingRequest for thread-safe request handling
1e685e9
fix(ws): improve WebSocket client response handling and thread-safety
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,45 @@ | ||
| ## Summary | ||
| <!-- Explain the problem, context, and why this change is needed. Link to the issue. --> | ||
|
|
||
| Related issue: #____ | ||
| <!-- Briefly explain the problem and why this change is needed. --> | ||
|
|
||
| Closes #____ | ||
|
|
||
| ## Type of change | ||
|
|
||
| <!-- Check all that apply --> | ||
|
|
||
| - [ ] `fix` - Bug fix (non-breaking) | ||
| - [ ] `feat` - New feature (non-breaking) | ||
| - [ ] `refactor` - Code change that neither fixes a bug nor adds a feature | ||
| - [ ] `docs` - Documentation only | ||
| - [ ] `test` - Adding or updating tests | ||
| - [ ] `perf` - Performance improvement | ||
| - [ ] `chore` - Build, CI, or tooling changes | ||
|
|
||
| ## What changed? | ||
| <!-- Brief summary; suggest where to start reviewing if many files. --> | ||
|
|
||
| ## BREAKING | ||
| <!-- If applicable, call it out explicitly. --> | ||
| <!-- ⚠️ BREAKING: Describe migration or impact. --> | ||
| <!-- Brief summary of changes. For large PRs, suggest where to start reviewing. --> | ||
|
|
||
| ## Breaking changes | ||
|
|
||
| <!-- Delete this section if not applicable --> | ||
| <!-- ⚠️ BREAKING: Describe migration steps or impact on existing code. --> | ||
|
|
||
| ## Testing | ||
|
|
||
| <!-- How was this tested? Include commands, test classes, or manual verification steps. --> | ||
|
|
||
| - [ ] Unit tests pass: `mvn test` | ||
| - [ ] Integration tests pass: `mvn verify` (requires Docker) | ||
|
|
||
| ## Review focus | ||
| <!-- Ask for specific feedback, e.g., "Concurrency strategy OK?" or "API shape acceptable?" --> | ||
|
|
||
| <!-- Optional: Ask for specific feedback, e.g., "Is the error handling approach OK?" --> | ||
|
|
||
| ## Checklist | ||
| - [ ] Scope ≤ 300 lines (or split/stack) | ||
| - [ ] Title is **verb + object** (e.g., “Refactor auth middleware to async”) | ||
| - [ ] Description links the issue and answers “why now?” | ||
| - [ ] **BREAKING** flagged if needed | ||
| - [ ] Tests/docs updated (if relevant) | ||
|
|
||
| - [ ] PR title follows conventional commits: `type(scope): description` | ||
| - [ ] Changes are focused and under 300 lines (or stacked PRs) | ||
| - [ ] Tests added/updated for new functionality | ||
| - [ ] No new compiler warnings introduced | ||
| - [ ] CHANGELOG.md updated (for user-facing changes) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Project Overview | ||
|
|
||
| `nostr-java` is a Java SDK for the Nostr protocol. It provides utilities for creating, signing, and publishing Nostr events to relays. The project implements 20+ Nostr Implementation Possibilities (NIPs). | ||
|
|
||
| - **Language**: Java 21+ | ||
| - **Build Tool**: Maven | ||
| - **Architecture**: Multi-module Maven project with 9 modules | ||
|
|
||
| ## Module Architecture | ||
|
|
||
| The codebase follows a layered dependency structure. Understanding this hierarchy is essential for making changes: | ||
|
|
||
| 1. **nostr-java-util** – Foundation utilities (no dependencies on other modules) | ||
| 2. **nostr-java-crypto** – BIP340 Schnorr signatures (depends on util) | ||
| 3. **nostr-java-base** – Common model classes (depends on crypto, util) | ||
| 4. **nostr-java-event** – Event and tag definitions (depends on base, crypto, util) | ||
| 5. **nostr-java-id** – Identity and key handling (depends on base, crypto) | ||
| 6. **nostr-java-encryption** – Message encryption (depends on base, crypto, id) | ||
| 7. **nostr-java-client** – WebSocket relay client (depends on event, base) | ||
| 8. **nostr-java-api** – High-level API (depends on all above) | ||
| 9. **nostr-java-examples** – Sample applications (depends on api) | ||
|
|
||
| **Key principle**: Lower-level modules cannot depend on higher-level ones. When adding features, place code at the lowest appropriate level. | ||
|
|
||
| ## Common Development Commands | ||
|
|
||
| ### Building and Testing | ||
|
|
||
| ```bash | ||
| # Run all unit tests (no Docker required) | ||
| mvn clean test | ||
|
|
||
| # Run integration tests (requires Docker for Testcontainers) | ||
| mvn clean verify | ||
|
|
||
| # Run integration tests with verbose output | ||
| mvn -q verify | ||
|
|
||
| # Install artifacts without tests | ||
| mvn install -Dmaven.test.skip=true | ||
|
|
||
| # Run a specific test class | ||
| mvn -q test -Dtest=GenericEventBuilderTest | ||
|
|
||
| # Run a specific test method | ||
| mvn -q test -Dtest=GenericEventBuilderTest#testSpecificMethod | ||
| ``` | ||
|
|
||
| ### Code Quality | ||
|
|
||
| ```bash | ||
| # Verify code quality and run all checks | ||
| mvn -q verify | ||
|
|
||
| # Generate code coverage report (Jacoco) | ||
| mvn verify | ||
| # Reports: target/site/jacoco/index.html in each module | ||
| ``` | ||
|
|
||
| ## Key Architectural Patterns | ||
|
|
||
| ### Event System | ||
|
|
||
| - **GenericEvent** (`nostr-java-event/src/main/java/nostr/event/impl/GenericEvent.java`) is the core event class | ||
| - Events can be built using: | ||
| - Direct constructors with `PublicKey` and `Kind`/`Integer` | ||
| - Static `GenericEvent.builder()` for flexible construction | ||
| - All events must be signed before sending to relays | ||
| - Events support both NIP-defined kinds (via `Kind` enum) and custom kinds (via `Integer`) | ||
|
|
||
| ### Client Architecture | ||
|
|
||
| Two WebSocket client implementations: | ||
|
|
||
| 1. **StandardWebSocketClient** – Blocking, waits for relay responses with configurable timeout | ||
| 2. **NostrSpringWebSocketClient** – Non-blocking with Spring WebSocket and retry support (3 retries, exponential backoff from 500ms) | ||
|
|
||
| Configuration properties: | ||
| - `nostr.websocket.await-timeout-ms=60000` | ||
| - `nostr.websocket.poll-interval-ms=500` | ||
|
|
||
| ### Tag System | ||
|
|
||
| - Tags are represented by `BaseTag` and subclasses | ||
| - Custom tags can be registered via `TagRegistry` | ||
| - Serialization/deserialization handled by Jackson with custom serializers in `nostr.event.json.serializer` | ||
|
|
||
| ### Identity and Signing | ||
|
|
||
| - `Identity` class manages key pairs | ||
| - Events implement `ISignable` interface | ||
| - Signing uses Schnorr signatures (BIP340) | ||
| - Public keys use Bech32 encoding (npub prefix) | ||
|
|
||
| ## NIPs Implementation | ||
|
|
||
| The codebase implements NIPs through dedicated classes in `nostr-java-api`: | ||
| - NIP classes (e.g., `NIP01`, `NIP04`, `NIP25`) provide builder methods and utilities | ||
| - Event implementations in `nostr-java-event/src/main/java/nostr/event/impl/` | ||
| - Refer to `.github/copilot-instructions.md` for the full NIP specification links | ||
|
|
||
| When implementing new NIP support: | ||
| 1. Add event class in `nostr-java-event` if needed | ||
| 2. Create NIP helper class in `nostr-java-api` | ||
| 3. Add tests in both modules | ||
| 4. Update README.md with NIP reference | ||
| 5. Add example in `nostr-java-examples` | ||
|
|
||
| ## Testing Strategy | ||
|
|
||
| - **Unit tests** (`*Test.java`): No external dependencies, use mocks | ||
| - **Integration tests** (`*IT.java`): Use Testcontainers to start `nostr-rs-relay` | ||
| - Relay container image can be overridden in `src/test/resources/relay-container.properties` | ||
| - Integration tests may be retried once on failure (configured in failsafe plugin) | ||
|
|
||
| ## Code Standards | ||
|
|
||
| - **Commit messages**: Must follow conventional commits format: `type(scope): description` | ||
| - Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` | ||
| - See `commit_instructions.md` for full guidelines | ||
| - **PR target**: All PRs should target the `develop` branch | ||
| - **Code formatting**: Google Java Format (enforced by CI) | ||
| - **Test coverage**: Jacoco generates reports (enforced by CI) | ||
| - **Required**: All changes must include unit tests and documentation updates | ||
|
|
||
| ## Dependency Management | ||
|
|
||
| - **BOM**: `nostr-java-bom` (version 1.1.1) manages all dependency versions | ||
| - Root `pom.xml` includes temporary module version overrides until next BOM release | ||
| - Never add version numbers to dependencies in child modules – let the BOM manage versions | ||
|
|
||
| ## Documentation | ||
|
|
||
| Comprehensive documentation in `docs/`: | ||
| - `docs/GETTING_STARTED.md` – Installation and setup | ||
| - `docs/howto/use-nostr-java-api.md` – API usage guide | ||
| - `docs/howto/streaming-subscriptions.md` – Subscription management | ||
| - `docs/howto/custom-events.md` – Creating custom event types | ||
| - `docs/reference/nostr-java-api.md` – API reference | ||
| - `docs/CODEBASE_OVERVIEW.md` – Module layout and build instructions | ||
|
|
||
| ## Common Patterns and Gotchas | ||
|
|
||
| ### Event Building | ||
| ```java | ||
| // Using builder for custom kinds | ||
| GenericEvent event = GenericEvent.builder() | ||
| .kind(customKindInteger) | ||
| .content("content") | ||
| .pubKey(publicKey) | ||
| .build(); | ||
|
|
||
| // Using constructor for standard kinds | ||
| GenericEvent event = new GenericEvent(pubKey, Kind.TEXT_NOTE); | ||
| ``` | ||
|
|
||
| ### Signing and Sending | ||
| ```java | ||
| // Sign and send pattern | ||
| EventNostr nostr = new NIP01(identity); | ||
| nostr.createTextNote("Hello Nostr!") | ||
| .sign() | ||
| .send(relays); | ||
| ``` | ||
|
|
||
| ### Custom Tags | ||
| Register custom tags in `TagRegistry` before deserializing events that contain them. | ||
|
|
||
| ### WebSocket Sessions | ||
| Spring WebSocket client maintains persistent connections. Always close subscriptions properly to avoid resource leaks. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| ## | ||
| ## strfry config for integration testing (no whitelist) | ||
| ## | ||
|
|
||
| db = "./strfry-db/" | ||
|
|
||
| dbParams { | ||
| maxreaders = 256 | ||
| mapsize = 10995116277760 | ||
| noReadAhead = false | ||
| } | ||
|
|
||
| events { | ||
| maxEventSize = 65536 | ||
| rejectEventsNewerThanSeconds = 900 | ||
| rejectEventsOlderThanSeconds = 94608000 | ||
| rejectEphemeralEventsOlderThanSeconds = 60 | ||
| ephemeralEventsLifetimeSeconds = 300 | ||
| maxNumTags = 2000 | ||
| maxTagValSize = 1024 | ||
| } | ||
|
|
||
| relay { | ||
| bind = "0.0.0.0" | ||
| port = 7777 | ||
| nofiles = 1000000 | ||
| realIpHeader = "" | ||
|
|
||
| info { | ||
| name = "nostr-java test relay" | ||
| description = "strfry relay for nostr-java integration tests" | ||
| pubkey = "" | ||
| contact = "" | ||
| icon = "" | ||
| nips = "" | ||
| } | ||
|
|
||
| maxWebsocketPayloadSize = 131072 | ||
| maxReqFilterSize = 200 | ||
| autoPingSeconds = 55 | ||
| enableTcpKeepalive = false | ||
| queryTimesliceBudgetMicroseconds = 10000 | ||
| maxFilterLimit = 500 | ||
| maxSubsPerConnection = 20 | ||
|
|
||
| writePolicy { | ||
| # No write policy plugin - accept all events | ||
| plugin = "" | ||
| } | ||
|
|
||
| compression { | ||
| enabled = true | ||
| slidingWindow = true | ||
| } | ||
|
|
||
| logging { | ||
| dumpInAll = false | ||
| dumpInEvents = false | ||
| dumpInReqs = false | ||
| dbScanPerf = false | ||
| invalidEvents = true | ||
| } | ||
|
|
||
| numThreads { | ||
| ingester = 3 | ||
| reqWorker = 3 | ||
| reqMonitor = 3 | ||
| negentropy = 2 | ||
| } | ||
|
|
||
| negentropy { | ||
| enabled = true | ||
| maxSyncEvents = 1000000 | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.