Repository navigation
Absorb outline-br, and fix certificate pinning across multiple requests - #7
Merged
Merged
Conversation
outline-br and ShadowboxKeys both listed Outline access keys and rewrote their URLs for a new host; ShadowboxKeys had since grown most of outline-br's roadmap. Merge them so there is one project. - index.js exposes the library outline-br provided: listKeys() and getUsage() return structured data, and getKeys() is kept signature-compatible with outline-br, same output format and printing, additionally returning the lines and accepting certSha256. - package main points at the library; the CLI stays the bin entry, and files/ limits what gets packed. - MIT LICENSE and the Contributor Covenant come across from outline-br. The licence is rewritten with the project's own copyright line rather than copying outline-br's, which carried an unrelated holder. - README documents module usage and how to migrate from outline-br. Fix certificate pinning across multiple requests ------------------------------------------------ The new integration tests, which drive a real HTTPS server, caught a bug in the pinning merged in #6: with TLS session resumption the second connection skips the certificate exchange, so getPeerCertificate() returned nothing and the check rejected the legitimate server. Every command issuing more than one request (add, remove, rename, limit) was affected whenever a fingerprint was configured; the earlier testing missed it by only pairing correct fingerprints with single-request commands. Disabling the agent's TLS session cache forces a full handshake per request. Covered by a regression test that fails without the fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QJR2DDBimsijgYgZS3bUS8
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Merges outline-br into this project, and fixes a pinning bug the new tests uncovered.
Why merge them
Both projects listed Outline access keys and rewrote their URLs for a new host. outline-br did it as a published module; ShadowboxKeys did it as a CLI and has since grown most of what outline-br's README listed under "Coming Soon" — mass key management from the terminal, data limits, usage tracking. Keeping two overlapping tools costs more than it earns.
The package keeps the name
shadowbox-keys. outline-br stays on npm frozen at 2.0.2, and its repository should get a deprecation note pointing here — I don't have push access to it, so that one is yours (or say the word and I'll request it).The library API
index.jsbecomes the package entry point, so everything the CLI does is now reachable from code:OutlineClientis exported for the rest — create, rename, delete, per-key and server-wide data limits.outline-br compatibility
getKeys(managementApiUrl, newDomain)keeps outline-br's signature, itsName -> ss://...output format (including the trimmed/?outline=1andNonamefor unnamed keys) and its printing behaviour. Callers change their import and nothing else:Two additive differences: it now also returns the lines it printed, and takes an optional third argument for
certSha256.Bug fix: pinning broke on the second request
The new integration tests drive a real HTTPS server, and immediately caught a bug in the certificate pinning merged in #4383973007 (#6):
With TLS session resumption, the second connection skips the certificate exchange.
getPeerCertificate()returned nothing, so the check compared the configured fingerprint against(none)and rejected the legitimate server. Any command issuing more than one request —add,remove,rename,limit— failed for anyone who had configured a fingerprint.Reproduced on the CLI before fixing:
My earlier testing missed it by only ever pairing a correct fingerprint with single-request commands, and a wrong fingerprint with multi-request ones — which fails on request one regardless. The fix disables the agent's TLS session cache (
maxCachedSessions: 0) so every request completes a full handshake. Cost is a few milliseconds per request; the guarantee is that the check always has a certificate to inspect. It fails closed either way, so no connection was ever wrongly trusted.A regression test covers it, and I confirmed it fails without the fix.
Also
LICENSEand the Contributor Covenant come across from outline-br. The licence is rewritten with this project's own copyright line — outline-br's copy carried an unrelated holder (Kadira Inc.), which looked like a paste artefact rather than anything intended. Worth a look in case you want a different name or year.filesadded to package.json so a publish ships onlyindex.js,shadowboxKey.jsandlib/.index.jsand verifies the module's exports load.Testing
39 tests, all passing. The 8 new ones are true integration tests: they generate a throwaway self-signed certificate, start a real HTTPS server, and exercise
listKeys,getUsage,getKeys, host rewriting, and pinning in both the matching and mismatched cases — including the multi-request regression. They skip cleanly whereopensslis unavailable.Separately, I ran every code sample in the new README section against a mock Management API to confirm the documented shapes and outputs are accurate, and checked
npm packships the intended files.Generated by Claude Code