feat: add dynamic authorization support via callback provider#194
feat: add dynamic authorization support via callback provider#194EddieHouston wants to merge 1 commit intobitcoindevkit:masterfrom
Conversation
7e9324b to
db94491
Compare
|
concept ACK Thanks for this, adding an "authorization" header is the most common way to authenticate to a http endpoints so this should be generally useful. Appreciate the comprehensive examples and unit tests. The team is spread a bit thin so it may take some time to get it reviewed and tested. |
oleonardolima
left a comment
There was a problem hiding this comment.
cACK
I did an initial round of review. Overall, it looks good! I'll give it a try testing it.
|
@EddieHouston needs rebase |
@oleonardolima Was this still planned to release before the Electrum protocol v1.6 changes? |
I'm planning to have both under the same release, as the version negotiation is should work fine for new v1.6 and old servers. Appreciate it, if you could do a rebase. |
|
Also, you could use the opportunity to squash into a single commit, as it touches the same files. |
db94491 to
3781f4d
Compare
Looks like changes for electrum protocol v1.6 break this. The new negotiate_protocol_version are automatically called from constructors... those need to now pass auth as well so the call to server.version can succeed. |
3781f4d to
ca27c4a
Compare
I asked Claude Code to fix this issue (squashed the change and force pushed): Here's the old flow: RawClient::new_ssl(url, validate_domain, timeout) // 1. creates stream The electrum server requiring auth also requires auth on server.version, so step 2 fails before we ever get to step 4. The _with_auth constructors fix the ordering: RawClient::new_ssl_with_auth(url, validate_domain, timeout, auth_provider) Tested locally and this works. |
@EddieHouston It looks like Claude didn't fully fixed the issues, CI is failing. |
I asked it to fix it, and it gave this suggestions, see: 17fc5b6 Oh, still failing though 🤦 |
The CI runs with --no-default-features --features proxy (no SSL). @oleonardolima Updated with fix. Ran the |
ca27c4a to
3590cea
Compare
3590cea to
09345de
Compare
|
@oleonardolima I'll ran these locally and resolved the issues: Newbee question... Is there an easy way to run all the CI test locally? |
1. fmtcargo fmt --all -- --config format_code_in_doc_comments=true --check 2. clippycargo clippy --all-features --all-targets -- -D warnings 3. testscargo test --verbose --all-features 4. check all feature combinationscargo check --verbose --features default 5.rustup toolchain install 1.75.0 |
oleonardolima
left a comment
There was a problem hiding this comment.
utACK 09345de
It looks good, though I'm wondering what's the rationale on adding new methods, instead of update the existing ones APIs. Did you want to reduce the number of breaking changes ?
I'll come up with a patch with some changes I have in mind, to see if the API would be better.
| #[test] | ||
| fn test_authorization_field_omitted_when_none() { | ||
| let req = Request::new_id(1, "test.method", vec![]); | ||
|
|
||
| let json = serde_json::to_string(&req).unwrap(); | ||
|
|
||
| // The JSON should not contain the word "authorization" at all | ||
| assert!(!json.contains("authorization")); | ||
| } |
There was a problem hiding this comment.
nit: can't you could just move this assertion to the first test ?
| /// The protocol version negotiated with the server via `server.version`. | ||
| protocol_version: Mutex<Option<String>>, | ||
|
|
||
| auth_provider: Option<AuthProvider>, |
There was a problem hiding this comment.
nit: could use documentation
| /// This sends `server.version` as the first message and stores the negotiated | ||
| /// protocol version. Called automatically by constructors. | ||
| fn negotiate_protocol_version(&self) -> Result<(), Error> { | ||
| pub(crate) fn negotiate_protocol_version(&self) -> Result<(), Error> { |
There was a problem hiding this comment.
question: what's the rationale on making this pub(crate) ? I didn't see any new usage of it.
Description
This PR adds support for dynamic authorization in Electrum RPC requests.
This enables authentication with authorization-protected Electrum servers and API gateways.
Use cases:
Notes to the reviewers
The implementation uses a callback pattern rather than a static token to support dynamic scenarios like automatic token refresh. The
AuthProvideris called for each RPC request, allowing the token to be updated without reconnecting the client.Both
ConfigandRawClientstructs needed customDebugimplementations since function pointers don't implementDebug- this is handled by displaying<provider>when an auth provider is present, which prevents leaking sensitive token values in debug output.Thread safety is ensured through
Arcwrapping andSend + Syncbounds, making this safe for concurrent use across the client.Tests added:
14 new tests, all passing
Changelog notice
Added: Dynamic authorization support via
AuthProvidercallback inConfigBuilder. Enables authentication with authorization-protected Electrum servers and automatic token refresh patterns for Bearer tokens, API keys, and other authorization schemes.Checklists
All Submissions:
New Features:
Bugfixes: