javascript-solid-server 0.0.110 → 0.0.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,109 @@
1
+ ## ActivityPub Federation
2
+
3
+ Enable ActivityPub to federate with Mastodon, Pleroma, Misskey, and other Fediverse servers:
4
+
5
+ ```bash
6
+ jss start --activitypub --ap-username alice --ap-display-name "Alice" --ap-summary "Hello from JSS!"
7
+ ```
8
+
9
+ ### Endpoints
10
+
11
+ | Endpoint | Description |
12
+ |----------|-------------|
13
+ | `/.well-known/webfinger` | Actor discovery (Mastodon searches here) |
14
+ | `/.well-known/nodeinfo` | NodeInfo discovery |
15
+ | `/profile/card` | Actor (returns JSON-LD when `Accept: application/activity+json`) |
16
+ | `/inbox` | Shared inbox for receiving activities |
17
+ | `/profile/card/inbox` | Personal inbox |
18
+ | `/profile/card/outbox` | User's activities |
19
+ | `/profile/card/followers` | Followers collection |
20
+ | `/profile/card/following` | Following collection |
21
+
22
+ ### How It Works
23
+
24
+ 1. **Discovery**: Mastodon looks up `@alice@your.server` via WebFinger
25
+ 2. **Actor**: Returns ActivityPub Actor JSON-LD with public key
26
+ 3. **Follow**: Remote servers POST Follow activities to inbox
27
+ 4. **Accept**: JSS auto-accepts follows and sends Accept back
28
+ 5. **Delivery**: Posts are signed with HTTP Signatures and delivered to follower inboxes
29
+
30
+ ### Identity Linking
31
+
32
+ Your WebID (`/profile/card#me`) becomes your ActivityPub Actor. Link to Nostr identity:
33
+
34
+ ```bash
35
+ jss start --activitypub --ap-nostr-pubkey <64-char-hex-pubkey>
36
+ ```
37
+
38
+ This adds `alsoKnownAs: ["did:nostr:<pubkey>"]` to your Actor profile, creating a verifiable link between your Solid, ActivityPub, and Nostr identities (the SAND stack).
39
+
40
+ ### Programmatic Usage
41
+
42
+ ```javascript
43
+ import { createServer } from 'javascript-solid-server';
44
+
45
+ const server = createServer({
46
+ activitypub: true,
47
+ apUsername: 'alice',
48
+ apDisplayName: 'Alice',
49
+ apSummary: 'Building the decentralized web!',
50
+ apNostrPubkey: 'abc123...' // Optional: links to did:nostr
51
+ });
52
+ ```
53
+
54
+ ### Testing Federation
55
+
56
+ ```bash
57
+ # Check WebFinger
58
+ curl "http://localhost:3000/.well-known/webfinger?resource=acct:alice@localhost:3000"
59
+
60
+ # Get Actor (AP format)
61
+ curl -H "Accept: application/activity+json" http://localhost:3000/profile/card
62
+
63
+ # Check NodeInfo
64
+ curl http://localhost:3000/.well-known/nodeinfo/2.1
65
+ ```
66
+
67
+ ## Mastodon-compatible API
68
+
69
+ JSS exposes Mastodon API endpoints so that Mastodon clients (Elk, Phanpy, Ice Cubes) can connect:
70
+
71
+ ```bash
72
+ jss start --activitypub --idp
73
+ ```
74
+
75
+ ### Endpoints
76
+
77
+ | Endpoint | Description |
78
+ |----------|-------------|
79
+ | `POST /api/v1/apps` | Dynamic client registration |
80
+ | `GET /api/v1/accounts/verify_credentials` | Current user profile |
81
+ | `GET /api/v1/instance` | Instance metadata |
82
+ | `GET /oauth/authorize` | OAuth authorize page |
83
+ | `POST /oauth/authorize` | Process login |
84
+ | `POST /oauth/token` | Exchange code for Bearer token |
85
+
86
+ ### OAuth 2.0 Flow
87
+
88
+ The OAuth layer is shared between Mastodon clients, remoteStorage apps, and third-party Solid panes:
89
+
90
+ 1. Client registers via `POST /api/v1/apps` (gets `client_id` + `client_secret`)
91
+ 2. Client redirects user to `GET /oauth/authorize?client_id=...&redirect_uri=...&response_type=code`
92
+ 3. User logs in, JSS redirects back with `?code=...`
93
+ 4. Client exchanges code for Bearer token via `POST /oauth/token`
94
+ 5. Bearer token works with all JSS endpoints (Solid, ActivityPub, remoteStorage)
95
+
96
+ Supports out-of-band (OOB) redirect for CLI/desktop clients.
97
+
98
+ ### Testing
99
+
100
+ ```bash
101
+ # Register a client
102
+ curl -X POST http://localhost:3000/api/v1/apps \
103
+ -H "Content-Type: application/json" \
104
+ -d '{"client_name": "Test App", "redirect_uris": "urn:ietf:wg:oauth:2.0:oob"}'
105
+
106
+ # Check instance info
107
+ curl http://localhost:3000/api/v1/instance
108
+ ```
109
+
@@ -0,0 +1,165 @@
1
+ ## Pod Structure
2
+
3
+ ```
4
+ /alice/
5
+ ├── index.html # WebID profile (HTML with JSON-LD)
6
+ ├── .acl # Root ACL (owner + public read)
7
+ ├── inbox/ # Notifications (public append)
8
+ │ └── .acl
9
+ ├── public/ # Public files
10
+ ├── private/ # Private files (owner only)
11
+ │ └── .acl
12
+ └── settings/ # User preferences (owner only)
13
+ ├── .acl
14
+ ├── prefs
15
+ ├── publicTypeIndex
16
+ └── privateTypeIndex
17
+ ```
18
+
19
+ ## Project Structure
20
+
21
+ ```
22
+ src/
23
+ ├── index.js # Entry point
24
+ ├── server.js # Fastify setup
25
+ ├── handlers/
26
+ │ ├── resource.js # GET, PUT, DELETE, HEAD, PATCH
27
+ │ ├── container.js # POST, pod creation
28
+ │ ├── git.js # Git HTTP backend
29
+ │ └── pay.js # HTTP 402 paid access
30
+ ├── storage/
31
+ │ ├── filesystem.js # File operations
32
+ │ └── quota.js # Storage quota management
33
+ ├── auth/
34
+ │ ├── middleware.js # Auth hook
35
+ │ ├── token.js # Simple token auth
36
+ │ ├── solid-oidc.js # DPoP verification
37
+ │ ├── nostr.js # NIP-98 Nostr authentication
38
+ │ ├── did-nostr.js # did:nostr → WebID resolution
39
+ │ └── webid-tls.js # WebID-TLS client certificate auth
40
+ ├── wac/
41
+ │ ├── parser.js # ACL parsing
42
+ │ └── checker.js # Permission checking
43
+ ├── ldp/
44
+ │ ├── headers.js # LDP Link headers
45
+ │ └── container.js # Container JSON-LD
46
+ ├── webid/
47
+ │ └── profile.js # WebID generation
48
+ ├── patch/
49
+ │ ├── n3-patch.js # N3 Patch support
50
+ │ └── sparql-update.js # SPARQL Update support
51
+ ├── notifications/
52
+ │ ├── index.js # WebSocket plugin
53
+ │ ├── events.js # Event emitter
54
+ │ └── websocket.js # solid-0.1 protocol
55
+ ├── idp/
56
+ │ ├── index.js # Identity Provider plugin
57
+ │ ├── provider.js # oidc-provider config
58
+ │ ├── adapter.js # Filesystem adapter
59
+ │ ├── accounts.js # User account management
60
+ │ ├── credentials.js # Credentials endpoint
61
+ │ ├── keys.js # JWKS key management
62
+ │ ├── interactions.js # Login/consent handlers
63
+ │ ├── passkey.js # WebAuthn/FIDO2 passkey support
64
+ │ ├── views.js # HTML templates
65
+ │ └── invites.js # Invite code management
66
+ ├── ap/
67
+ │ ├── index.js # ActivityPub plugin
68
+ │ ├── keys.js # RSA keypair management
69
+ │ ├── store.js # SQLite storage (followers, activities)
70
+ │ └── routes/
71
+ │ ├── actor.js # Actor JSON-LD
72
+ │ ├── inbox.js # Receive activities
73
+ │ ├── outbox.js # User's activities
74
+ │ ├── collections.js # Followers/following
75
+ │ ├── mastodon.js # Mastodon API (apps, instance, verify_credentials)
76
+ │ └── oauth.js # OAuth 2.0 authorize/token flow
77
+ ├── webledger.js # Web Ledger balance tracking (webledgers.org)
78
+ ├── mrc20.js # State chain verification
79
+ ├── remotestorage.js # remoteStorage protocol (draft-dejong-remotestorage-22)
80
+ ├── rdf/
81
+ │ ├── turtle.js # Turtle <-> JSON-LD
82
+ │ └── conneg.js # Content negotiation
83
+ ├── mashlib/
84
+ │ └── index.js # Mashlib data browser plugin
85
+ └── utils/
86
+ ├── url.js # URL utilities
87
+ ├── conditional.js # If-Match/If-None-Match
88
+ └── ssrf.js # SSRF protection
89
+ ```
90
+
91
+ ## Dependencies
92
+
93
+ 14 direct dependencies for a fast, secure server:
94
+
95
+ - **fastify** - High-performance HTTP server
96
+ - **@fastify/middie** - Express/Connect middleware bridge (for IdP)
97
+ - **@fastify/rate-limit** - Rate limiting for API endpoints
98
+ - **@fastify/websocket** - WebSocket support for notifications
99
+ - **@simplewebauthn/server** - Passkey/WebAuthn authentication
100
+ - **bcryptjs** - Password hashing (pure JS, works on Termux/Android)
101
+ - **commander** - CLI command parsing
102
+ - **fs-extra** - Enhanced file operations
103
+ - **jose** - JWT/JWK handling for Solid-OIDC
104
+ - **microfed** - ActivityPub primitives (only when activitypub enabled)
105
+ - **n3** - Turtle parsing (only used when conneg enabled)
106
+ - **nostr-tools** - Nostr protocol and Schnorr signature verification
107
+ - **oidc-provider** - OpenID Connect Identity Provider (only when IdP enabled)
108
+ - **sql.js** - SQLite storage for federation data (WASM, cross-platform)
109
+
110
+ ## Performance
111
+
112
+ This server is designed for speed. Benchmark results on a typical development machine:
113
+
114
+ | Operation | Requests/sec | Avg Latency | p99 Latency |
115
+ |-----------|-------------|-------------|-------------|
116
+ | GET resource | 5,400+ | 1.2ms | 3ms |
117
+ | GET container | 4,700+ | 1.6ms | 3ms |
118
+ | PUT (write) | 5,700+ | 1.1ms | 2ms |
119
+ | POST (create) | 5,200+ | 1.3ms | 3ms |
120
+ | OPTIONS | 10,000+ | 0.4ms | 1ms |
121
+
122
+ Run benchmarks yourself:
123
+ ```bash
124
+ npm run benchmark
125
+ ```
126
+
127
+ ## Running Tests
128
+
129
+ ```bash
130
+ npm test
131
+ ```
132
+
133
+ Currently passing: **289 tests** (including 27 conformance tests)
134
+
135
+ ### Conformance Test Harness (CTH)
136
+
137
+ This server passes the Solid Conformance Test Harness authentication tests:
138
+
139
+ ```bash
140
+ # Start server with IdP and content negotiation
141
+ JSS_PORT=4000 JSS_CONNEG=true JSS_IDP=true jss start
142
+
143
+ # Create test users
144
+ curl -X POST http://localhost:4000/.pods \
145
+ -H "Content-Type: application/json" \
146
+ -d '{"name": "alice", "email": "alice@example.com", "password": "alicepassword123"}'
147
+
148
+ curl -X POST http://localhost:4000/.pods \
149
+ -H "Content-Type: application/json" \
150
+ -d '{"name": "bob", "email": "bob@example.com", "password": "bobpassword123"}'
151
+
152
+ # Run CTH authentication tests
153
+ docker run --rm --network=host \
154
+ -e SOLID_IDENTITY_PROVIDER="http://localhost:4000/" \
155
+ -e USERS_ALICE_WEBID="http://localhost:4000/alice/#me" \
156
+ -e USERS_ALICE_PASSWORD="alicepassword123" \
157
+ -e USERS_BOB_WEBID="http://localhost:4000/bob/#me" \
158
+ -e USERS_BOB_PASSWORD="bobpassword123" \
159
+ solidproject/conformance-test-harness:latest \
160
+ --filter="authentication"
161
+ ```
162
+
163
+ **CTH Status (v0.0.15):**
164
+ - Authentication tests: 6/6 passing
165
+
@@ -0,0 +1,157 @@
1
+ # Authentication
2
+
3
+ ### Simple Tokens (Development)
4
+
5
+ Use the token returned from pod creation:
6
+
7
+ ```bash
8
+ curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/alice/private/
9
+ ```
10
+
11
+ ### Built-in Identity Provider (v0.0.12+)
12
+
13
+ Enable the built-in Solid-OIDC Identity Provider:
14
+
15
+ ```bash
16
+ jss start --idp
17
+ ```
18
+
19
+ With IdP enabled, pod creation requires email and password:
20
+
21
+ ```bash
22
+ curl -X POST http://localhost:3000/.pods \
23
+ -H "Content-Type: application/json" \
24
+ -d '{"name": "alice", "email": "alice@example.com", "password": "secret123"}'
25
+ ```
26
+
27
+ Response:
28
+ ```json
29
+ {
30
+ "name": "alice",
31
+ "webId": "http://localhost:3000/alice/#me",
32
+ "podUri": "http://localhost:3000/alice/",
33
+ "idpIssuer": "http://localhost:3000",
34
+ "loginUrl": "http://localhost:3000/idp/auth"
35
+ }
36
+ ```
37
+
38
+ OIDC Discovery: `/.well-known/openid-configuration`
39
+
40
+ ### Programmatic Login (CTH Compatible)
41
+
42
+ For automated testing and scripts, use the credentials endpoint:
43
+
44
+ ```bash
45
+ curl -X POST http://localhost:3000/idp/credentials \
46
+ -H "Content-Type: application/json" \
47
+ -d '{"email": "alice@example.com", "password": "secret123"}'
48
+ ```
49
+
50
+ Response:
51
+ ```json
52
+ {
53
+ "access_token": "...",
54
+ "token_type": "Bearer",
55
+ "expires_in": 3600,
56
+ "webid": "http://localhost:3000/alice/#me"
57
+ }
58
+ ```
59
+
60
+ For DPoP-bound tokens (Solid-OIDC compliant), include a DPoP proof header.
61
+
62
+ ### Passkey Authentication (v0.0.77+)
63
+
64
+ Enable passwordless login with WebAuthn/FIDO2:
65
+
66
+ ```bash
67
+ jss start --idp
68
+ ```
69
+
70
+ **How it works:**
71
+ 1. User logs in with username/password
72
+ 2. Prompted to add a passkey (Touch ID, Face ID, security key)
73
+ 3. Future logins: tap "Sign in with Passkey" → biometric → done!
74
+
75
+ **Benefits:**
76
+ - Phishing-resistant (bound to domain)
77
+ - No passwords to remember or leak
78
+ - Works on mobile and desktop
79
+
80
+ Passkeys are stored per-account and work across devices via platform sync (iCloud Keychain, Google Password Manager, etc.).
81
+
82
+ ### Schnorr SSO (v0.0.79+)
83
+
84
+ Sign in with your Nostr key using NIP-07 browser extensions:
85
+
86
+ ```bash
87
+ jss start --idp
88
+ ```
89
+
90
+ **How it works:**
91
+ 1. User clicks "Sign in with Schnorr" on the login page
92
+ 2. NIP-07 extension (Podkey, nos2x, Alby) signs a NIP-98 auth event
93
+ 3. Server verifies BIP-340 Schnorr signature
94
+ 4. User authenticated via linked did:nostr identity
95
+
96
+ **Requirements:**
97
+ - Account must have a `did:nostr:<pubkey>` WebID linked
98
+ - User needs a NIP-07 compatible browser extension
99
+
100
+ **Benefits:**
101
+ - No passwords - cryptographic authentication
102
+ - Works with existing Nostr identity
103
+ - Single sign-on across Solid and Nostr ecosystems
104
+
105
+ ### Solid-OIDC (External IdP)
106
+
107
+ The server also accepts DPoP-bound access tokens from external Solid identity providers:
108
+
109
+ ```bash
110
+ curl -H "Authorization: DPoP ACCESS_TOKEN" \
111
+ -H "DPoP: DPOP_PROOF" \
112
+ http://localhost:3000/alice/private/
113
+ ```
114
+
115
+ ### WebID-TLS (Client Certificates)
116
+
117
+ For backend services, CLI tools, and automated agents that need non-interactive authentication:
118
+
119
+ ```bash
120
+ jss start --ssl-key key.pem --ssl-cert cert.pem --webid-tls
121
+ ```
122
+
123
+ **How it works:**
124
+ 1. Client presents X.509 certificate during TLS handshake
125
+ 2. Certificate's `SubjectAlternativeName` contains a WebID URI
126
+ 3. Server fetches the WebID profile
127
+ 4. Server verifies the certificate's public key matches one in the profile
128
+
129
+ **Testing with curl:**
130
+
131
+ ```bash
132
+ # Generate self-signed cert with WebID in SAN
133
+ openssl req -x509 -newkey rsa:2048 -keyout client-key.pem -out client-cert.pem -days 365 \
134
+ -subj "/CN=Test" -addext "subjectAltName=URI:https://example.com/alice/#me" -nodes
135
+
136
+ # Make authenticated request
137
+ curl --cert client-cert.pem --key client-key.pem https://localhost:8443/alice/private/
138
+ ```
139
+
140
+ **Profile requirement:** Your WebID profile must contain the certificate's public key:
141
+
142
+ ```turtle
143
+ @prefix cert: <http://www.w3.org/ns/auth/cert#> .
144
+
145
+ <#me> cert:key [
146
+ a cert:RSAPublicKey;
147
+ cert:modulus "abc123..."^^xsd:hexBinary;
148
+ cert:exponent 65537
149
+ ] .
150
+ ```
151
+
152
+ **Use cases:**
153
+ - Enterprise backend services with existing PKI
154
+ - Server-to-server communication
155
+ - CLI tools and scripts
156
+ - IoT devices with embedded certificates
157
+