# Milestone 18: Inter-App Communication

**Status**: Complete
**Goal**: Kernel-mediated message passing between apps.

---

## Overview

This milestone implements secure inter-app communication via an intent system:
- Apps register to receive specific intent actions
- Senders must have required permissions
- All messages go through kernel mediation (no direct app-to-app)
- Message size limits prevent resource exhaustion
- Audit logging for all inter-app communication

### Key Deliverables

1. **MessageBus class** - Central message routing and validation
2. **Intent struct** - Message format with action, type, and data
3. **Lua intents API** - `intents.send()`, `intents.on()`, `intents.broadcast()`
4. **Security validation** - Permission checks, sender/receiver verification

---

## File Structure

```
src/main/cpp/sandbox/
├── message_bus.h      # NEW - Message bus API header
└── message_bus.cpp    # NEW - Message bus implementation
```

---

## Implementation Details

### 1. MessageBus Class

```cpp
// message_bus.h
#pragma once

#include <string>
#include <vector>
#include <functional>
#include <mutex>
#include <unordered_map>
#include <unordered_set>

struct lua_State;

namespace mosis {

struct Intent {
    std::string action;      // Intent action (e.g., "share", "view", "edit")
    std::string type;        // MIME type (e.g., "text/plain", "image/png")
    std::string data;        // Intent data/payload
    std::string from_app;    // Sender app ID (set by kernel)
};

struct IntentFilter {
    std::string action;      // Required action
    std::vector<std::string> types;  // Accepted MIME types (empty = all)
};

enum class MessageError {
    None,
    NoReceivers,
    PermissionDenied,
    InvalidIntent,
    DataTooLarge,
    ReceiverNotFound,
    SenderBlocked
};

class MessageBus {
public:
    using IntentHandler = std::function<void(const Intent&)>;

    MessageBus();
    ~MessageBus();

    // Register an app to receive intents
    void RegisterReceiver(
        const std::string& app_id,
        const IntentFilter& filter,
        IntentHandler handler
    );

    // Unregister all handlers for an app
    void UnregisterApp(const std::string& app_id);

    // Send intent to specific app (requires permission)
    MessageError Send(
        const std::string& sender_app,
        const std::string& target_app,
        const Intent& intent,
        std::string& error
    );

    // Broadcast intent to all registered receivers
    MessageError Broadcast(
        const std::string& sender_app,
        const Intent& intent,
        std::string& error
    );

    // Check if any app handles this action
    bool HasReceiverFor(const std::string& action) const;

    // Get list of apps that handle an action
    std::vector<std::string> GetReceiversFor(const std::string& action) const;

    // Permission management
    void SetAppPermission(const std::string& app_id, const std::string& permission, bool granted);
    bool HasPermission(const std::string& app_id, const std::string& permission) const;

    // Block specific app from sending/receiving
    void BlockApp(const std::string& app_id);
    void UnblockApp(const std::string& app_id);
    bool IsBlocked(const std::string& app_id) const;

    // Clear all registrations (for testing)
    void Clear();

    // Statistics
    size_t GetReceiverCount() const;
    size_t GetMessageCount() const { return m_message_count; }

private:
    struct ReceiverEntry {
        std::string app_id;
        IntentFilter filter;
        IntentHandler handler;
    };

    std::vector<ReceiverEntry> m_receivers;
    std::unordered_map<std::string, std::unordered_set<std::string>> m_permissions;
    std::unordered_set<std::string> m_blocked_apps;
    mutable std::mutex m_mutex;
    size_t m_message_count = 0;

    static constexpr size_t MAX_DATA_SIZE = 1024 * 1024;  // 1MB max

    bool MatchesFilter(const Intent& intent, const IntentFilter& filter) const;
    bool ValidateIntent(const Intent& intent, std::string& error) const;
};

// Register intents.* APIs as globals
void RegisterIntentsAPI(lua_State* L, MessageBus* bus, const std::string& app_id);

} // namespace mosis
```

### 2. Standard Intent Actions

| Action | Description | Required Permission |
|--------|-------------|---------------------|
| `share` | Share content with another app | None |
| `view` | Request app to view content | None |
| `edit` | Request app to edit content | None |
| `pick` | Request user to pick item | None |
| `call` | Initiate phone call | `phone.call` |
| `message` | Send SMS/message | `sms.send` |
| `email` | Compose email | None |

### 3. Permission Requirements

| Operation | Permission Required |
|-----------|---------------------|
| Send intent | Action-specific (see above) |
| Broadcast intent | Action-specific |
| Register receiver | None |
| Receive intent | None |

### 4. Lua API

```lua
-- Register to receive intents
intents.on("share", function(intent)
    print("Received share from:", intent.from)
    print("Type:", intent.type)
    print("Data:", intent.data)
end)

-- Register with MIME type filter
intents.on("view", function(intent)
    -- Handle view intent
end, {types = {"image/png", "image/jpeg"}})

-- Send intent to specific app
local success, err = intents.send("target.app.id", {
    action = "share",
    type = "text/plain",
    data = "Hello world"
})

-- Broadcast to all handlers
local count = intents.broadcast({
    action = "share",
    type = "text/plain",
    data = "Hello everyone"
})

-- Check if any app handles an action
local hasHandler = intents.hasReceiver("share")

-- Get list of apps that handle an action
local apps = intents.getReceivers("share")

-- Unregister all handlers for this app
intents.unregisterAll()
```

### 5. Error Handling

```lua
-- Errors raised via Lua errors
local ok, err = pcall(function()
    intents.send("target.app", {action = "share", data = "test"})
end)
if not ok then
    print("Error:", err)  -- e.g., "no receivers for action: share"
end
```

---

## Test Cases

### Test 1: Send to Registered Receiver

```cpp
bool Test_MessageBusSendToReceiver(std::string& error_msg) {
    mosis::MessageBus bus;

    bool received = false;
    mosis::Intent receivedIntent;

    // Register receiver
    bus.RegisterReceiver("receiver.app", {"share", {}}, [&](const mosis::Intent& i) {
        received = true;
        receivedIntent = i;
    });

    // Send intent
    mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
    std::string err;
    auto result = bus.Send("sender.app", "receiver.app", intent, err);

    EXPECT_TRUE(result == mosis::MessageError::None);
    EXPECT_TRUE(received);
    EXPECT_TRUE(receivedIntent.action == "share");
    EXPECT_TRUE(receivedIntent.data == "Hello");
    EXPECT_TRUE(receivedIntent.from_app == "sender.app");

    return true;
}
```

### Test 2: Block Unregistered Action

```cpp
bool Test_MessageBusBlockUnregistered(std::string& error_msg) {
    mosis::MessageBus bus;

    // No receivers registered
    mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
    std::string err;
    auto result = bus.Send("sender.app", "receiver.app", intent, err);

    EXPECT_TRUE(result == mosis::MessageError::ReceiverNotFound);
    EXPECT_TRUE(err.find("not found") != std::string::npos ||
                err.find("no receiver") != std::string::npos);

    return true;
}
```

### Test 3: Broadcast to Multiple Receivers

```cpp
bool Test_MessageBusBroadcast(std::string& error_msg) {
    mosis::MessageBus bus;

    int receiveCount = 0;

    // Register multiple receivers for same action
    bus.RegisterReceiver("app1", {"share", {}}, [&](const mosis::Intent&) { receiveCount++; });
    bus.RegisterReceiver("app2", {"share", {}}, [&](const mosis::Intent&) { receiveCount++; });
    bus.RegisterReceiver("app3", {"other", {}}, [&](const mosis::Intent&) { receiveCount++; });

    // Broadcast share intent
    mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
    std::string err;
    auto result = bus.Broadcast("sender.app", intent, err);

    EXPECT_TRUE(result == mosis::MessageError::None);
    EXPECT_TRUE(receiveCount == 2);  // Only app1 and app2

    return true;
}
```

### Test 4: MIME Type Filtering

```cpp
bool Test_MessageBusMimeFilter(std::string& error_msg) {
    mosis::MessageBus bus;

    bool imageReceived = false;
    bool textReceived = false;

    // Register with MIME filter
    bus.RegisterReceiver("image.viewer", {"view", {"image/png", "image/jpeg"}},
        [&](const mosis::Intent&) { imageReceived = true; });
    bus.RegisterReceiver("text.viewer", {"view", {"text/plain"}},
        [&](const mosis::Intent&) { textReceived = true; });

    // Send image intent
    mosis::Intent imgIntent{"view", "image/png", "data", "sender"};
    std::string err;
    bus.Broadcast("sender", imgIntent, err);

    EXPECT_TRUE(imageReceived);
    EXPECT_TRUE(!textReceived);

    return true;
}
```

### Test 5: Data Size Limit

```cpp
bool Test_MessageBusDataLimit(std::string& error_msg) {
    mosis::MessageBus bus;

    bus.RegisterReceiver("receiver", {"share", {}}, [](const mosis::Intent&) {});

    // Create oversized data (> 1MB)
    std::string largeData(2 * 1024 * 1024, 'x');

    mosis::Intent intent{"share", "text/plain", largeData, "sender"};
    std::string err;
    auto result = bus.Send("sender", "receiver", intent, err);

    EXPECT_TRUE(result == mosis::MessageError::DataTooLarge);

    return true;
}
```

### Test 6: Blocked App Cannot Send

```cpp
bool Test_MessageBusBlockedApp(std::string& error_msg) {
    mosis::MessageBus bus;

    bus.RegisterReceiver("receiver", {"share", {}}, [](const mosis::Intent&) {});
    bus.BlockApp("bad.app");

    mosis::Intent intent{"share", "text/plain", "Hello", "bad.app"};
    std::string err;
    auto result = bus.Send("bad.app", "receiver", intent, err);

    EXPECT_TRUE(result == mosis::MessageError::SenderBlocked);

    return true;
}
```

### Test 7: Lua Integration

```cpp
bool Test_MessageBusLuaIntegration(std::string& error_msg) {
    SandboxContext ctx = TestContext();
    LuaSandbox sandbox(ctx);

    mosis::MessageBus bus;
    mosis::RegisterIntentsAPI(sandbox.GetState(), &bus, "test.app");

    std::string script = R"lua(
        -- Test that intents global exists
        if not intents then
            error("intents global not found")
        end
        if not intents.on then
            error("intents.on not found")
        end
        if not intents.send then
            error("intents.send not found")
        end
        if not intents.broadcast then
            error("intents.broadcast not found")
        end
        if not intents.hasReceiver then
            error("intents.hasReceiver not found")
        end
        if not intents.getReceivers then
            error("intents.getReceivers not found")
        end
        if not intents.unregisterAll then
            error("intents.unregisterAll not found")
        end
    )lua";

    bool ok = sandbox.LoadString(script, "intents_test");
    if (!ok) {
        error_msg = "Lua test failed: " + sandbox.GetLastError();
        return false;
    }
    return true;
}
```

---

## Acceptance Criteria

All tests must pass:

- [x] `Test_MessageBusSendToReceiver` - Send reaches registered receiver
- [x] `Test_MessageBusBlockUnregistered` - Unregistered action fails
- [x] `Test_MessageBusBroadcast` - Broadcast reaches all matching receivers
- [x] `Test_MessageBusMimeFilter` - MIME type filtering works
- [x] `Test_MessageBusDataLimit` - Data size limit enforced
- [x] `Test_MessageBusBlockedApp` - Blocked apps cannot send
- [x] `Test_MessageBusLuaIntegration` - Lua API works

---

## Dependencies

- Milestone 1 (LuaSandbox)
- Milestone 2 (PermissionGate)
- Milestone 3 (AuditLog)

---

## Notes

### Security Considerations

1. **Kernel mediation**: All messages route through MessageBus, no direct app-to-app
2. **Sender verification**: `from_app` is set by kernel, cannot be spoofed
3. **Permission checks**: Sensitive actions require permissions
4. **Size limits**: 1MB max to prevent resource exhaustion
5. **App blocking**: Misbehaving apps can be blocked
6. **Audit logging**: All inter-app communication is logged

### Privacy Features

1. **Opt-in receiving**: Apps must explicitly register for actions
2. **MIME filtering**: Receivers can filter by content type
3. **No discovery**: Apps cannot enumerate other apps (only check receivers)

---

## Next Steps

After Milestone 18 passes:
1. Milestone 19: Security Testing Suite
