Skip to content

Feature: --public flag to skip WAC and allow open access #107

Description

@melvincarvalho

Summary

Add a --public flag that disables WAC (Web Access Control) checks, allowing unauthenticated read/write access to all resources. This enables JSS to be used as a simple file server similar to npx serve, but with REST write capabilities.

Difficulty: 15/100
Estimated Effort: 2-4 hours
Dependencies: None


Motivation

Currently, JSS requires either:

  1. ACL files to grant access, or
  2. Authentication via Solid-OIDC

This makes it impossible to use JSS as a simple "just serve this folder" tool like npx serve. The --public flag would enable:

  1. Quick local development - No auth setup needed
  2. Simple file sharing - LAN file server with write support
  3. jsserve wrapper - Foundation for npx jsserve (see future issue)
  4. WebDAV alternative - Simple REST-based file server
  5. Testing/demos - Quick Solid server without auth complexity

Proposed Implementation

CLI Flag

jss start --public              # Open read/write, no auth
jss start --public --read-only  # Open read, no writes (like npx serve)

Environment Variable

JSS_PUBLIC=true jss start

Config File

{
  "public": true
}

Implementation Details

1. Add flag to CLI (bin/jss.js)

.option('--public', 'Allow unauthenticated access to all resources (disables WAC)')
.option('--read-only', 'Disable PUT/DELETE methods (read-only mode)')

2. Add to config (src/config.js)

const DEFAULTS = {
  // ... existing ...
  public: false,
  readOnly: false,
};

// Environment variable mapping
if (process.env.JSS_PUBLIC) {
  config.public = process.env.JSS_PUBLIC === 'true';
}
if (process.env.JSS_READ_ONLY) {
  config.readOnly = process.env.JSS_READ_ONLY === 'true';
}

3. Skip WAC when public (src/auth/middleware.js)

export async function authorize(request, reply) {
  // Public mode - skip all auth/WAC checks
  if (request.config?.public) {
    return; // Allow request to proceed
  }
  
  // ... existing WAC logic ...
}

4. Block writes when read-only (src/handlers/resource.js, src/handlers/container.js)

// At start of PUT/DELETE handlers
if (request.config?.readOnly) {
  return reply.code(405).send({ 
    error: 'Method Not Allowed',
    message: 'Server is in read-only mode'
  });
}

Behavior Matrix

Flag Combination GET PUT/DELETE Auth Required
(default) ACL ACL Yes (if ACL requires)
--public ✅ Allow ✅ Allow No
--public --read-only ✅ Allow ❌ Block No
--read-only (no public) ACL ❌ Block Yes

Security Considerations

Warning on Startup

When --public is enabled, show a clear warning:

⚠️  WARNING: Server running in PUBLIC mode
   All files are readable and writable without authentication.
   Do not use in production or expose to the internet.

Binding to localhost by default?

Consider: When --public is set, should the default host be localhost instead of 0.0.0.0?

if (config.public && !explicitHostSet) {
  config.host = 'localhost'; // Safer default for public mode
}

User can override with --public --host 0.0.0.0 if they explicitly want network access.


Examples

Local Development

# Quick Solid-compatible file server for development
jss start --public --port 3000 --root ./test-data

Read-Only File Sharing

# Share files on LAN, no writes allowed
jss start --public --read-only --host 0.0.0.0 --root ~/shared

Testing Solid Apps

# Test app without auth complexity
jss start --public --root ./fixtures
npm test

Files to Modify

File Changes
bin/jss.js Add --public and --read-only options (~5 LOC)
src/config.js Add defaults and env var mapping (~10 LOC)
src/auth/middleware.js Skip WAC when public (~5 LOC)
src/handlers/resource.js Block writes when read-only (~5 LOC)
src/handlers/container.js Block writes when read-only (~5 LOC)
Total ~30 LOC

Testing

describe('--public flag', () => {
  it('should allow unauthenticated GET', async () => {
    const server = await createServer({ public: true, root: tmpDir });
    const res = await request(server).get('/file.txt');
    expect(res.status).toBe(200);
  });

  it('should allow unauthenticated PUT', async () => {
    const server = await createServer({ public: true, root: tmpDir });
    const res = await request(server)
      .put('/new-file.txt')
      .send('content');
    expect(res.status).toBe(201);
  });

  it('should block PUT when read-only', async () => {
    const server = await createServer({ public: true, readOnly: true, root: tmpDir });
    const res = await request(server)
      .put('/new-file.txt')
      .send('content');
    expect(res.status).toBe(405);
  });
});

Related Issues


Open Questions

  1. Should --public default to localhost binding for safety?
  2. Should there be a --public-read (read-only public) shorthand?
  3. Should --public disable IdP/login UI entirely, or just make it optional?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions