Skip to content

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

@melvincarvalho

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions