Commit 8796333
authored
S3-compatible API proxy over SMB 3.1.1 (#1)
* Add CLAUDE.md with project guidance for Claude Code
* Add design principles: reliability, performance, macOS 26+, SMB 3.1.x
* Add README with usage, configuration, and build instructions
* Initial commit: S3-compatible API proxy over SMB 3.1.1
- S3 layer: full API router with SigV4 auth, multipart uploads,
conditional writes, range reads, ListObjectsV1/V2, CopyObject,
multi-object Delete, and stub endpoints for ACL/tagging/versioning
- SMB layer: wire protocol client (negotiate, session setup, tree
connect, create, read, write, close, query directory, query info)
with NTLMv2/SPNEGO authentication
- Crypto: macOS CommonCrypto FFI (MD4, MD5, SHA-256, HMAC-MD5,
HMAC-SHA256) — zero external crypto dependencies
- Makefile with fmt, lint, clippy, test, build targets
- Targets macOS 26+, Rust 2024 edition
* Add streaming S3 transfers and sccache test flow
- add SpioBody for streaming HTTP responses
- stream GetObject reads from SMB to HTTP
- stream PutObject writes from HTTP to SMB
- add sccache integration test script and Makefile target
- update docs and dependency metadata
* Add streaming S3 transfers and sccache test flow
SMB protocol:
- Fix SPNEGO DER encoding for payloads >127 bytes
- Fix Create/Write request offset calculations (off-by-one)
- Fix Create/Write response minimum size checks
- Handle STATUS_PENDING by looping for final response
- Offer SMB 3.0.0/3.0.2 dialect fallbacks in negotiate
- Add NTLMSSP Version field and echo server negotiate flags
- Cap max read/write to 64KB to avoid oversized messages
SMB3 message signing:
- SHA-512 and AES-128-CMAC via CommonCrypto FFI
- SP800-108 KDF signing key derivation from session base key
- Preauth integrity hash tracking through handshake
- Sign all post-auth messages with AES-128-CMAC
S3 layer:
- Map SMB NotFound → S3 NoSuchKey (404), PermissionDenied → 403
- Streaming PutObject via channel-backed body
Test harness:
- make test runs sccache integration against SMB share
- Cold build populates cache, warm build verifies 100% hit rate
* Rename spio to spiceio, add AWS CLI S3 API tests
- Rename project, binary, env vars (SPIO_ → SPICEIO_), types (SpioBody → SpiceioBody)
- Add 14 AWS CLI tests: ListBuckets, HeadBucket, Put/Get (small/64KB/1MB with
integrity), HeadObject, ListObjectsV2, CopyObject, DeleteObject, nested paths,
overwrite
- Fix QueryDirectory request NameOffset (off-by-one, same as Create/Write)
- Test cleanup removes test objects from SMB share
* Address all 18 PR review comments
- Replace all get_u16_le/get_u32_le/get_u64_le on immutable slices
with from_le_bytes across protocol.rs and client.rs
- NtStatus: add Unknown(u32) variant to preserve raw status codes
instead of mapping unknowns to AccessDenied
- ListObjects: sort objects by key before marker/max-keys filtering
- RangeSpec::resolve: return Option, guard against underflow and
empty objects; return 416 for unsatisfiable ranges
- Unify ETag generation: re-read metadata after write so ETags
always derive from last_write_time
- Multipart completion: validate all parts exist before assembly,
defer state removal until success
- decode_read_response: parse DataOffset as u16 not u8
- Set RequestedOplockLevel to 0x00 (NONE) not 0x02
- Cap NetBIOS length to 0x00FFFFFF (3-byte max)1 parent 9d02d4f commit 8796333
20 files changed
Lines changed: 5710 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
0 commit comments