Browse Source

critical: Confirm plugin must know when activeDid changes

- Added critical requirement that plugin MUST be notified of activeDid changes
- Enhanced plugin interface with onActiveDidChange() callback method
- Added clearCacheForNewIdentity() and refreshAuthenticationForNewIdentity() methods
- Updated integration examples to include activeDid change listeners
- Created comprehensive ActiveDid change requirements document covering:
  * Security implications of not detecting changes
  * Event-based notification pattern implementation
  * Cache clearing and authentication refresh requirements
  * Testing scenarios for identity switching
  * Platform-specific considerations and edge cases
  * Performance optimization for rapid identity changes

This addresses the critical data integrity and security requirement that the plugin
must know when TimeSafari users switch identities to prevent data leakage.
research/notification-plugin-enhancement
Matthew Raymer 18 hours ago
parent
commit
1939b560d9
  1. 204
      doc/ACTIVE_DID_CHANGE_REQUIREMENTS.md
  2. 22
      doc/BACKGROUND_DATA_FETCHING_PLAN.md

204
doc/ACTIVE_DID_CHANGE_REQUIREMENTS.md

@ -0,0 +1,204 @@
# ActiveDid Change Requirements
**Author**: Matthew Raymer
**Version**: 1.0.0
**Created**: 2025-10-02 12:00:00 UTC
**Last Updated**: 2025-10-02 12:00:00 UTC
## Critical Requirement: Plugin Must Know When activeDid Changes
**CONFIRMED**: The plugin **must** be notified when activeDid changes to maintain data integrity and security.
## Why This Is Critical
### **Security Implications**
- **Authentication Isolation**: Each activeDid has different authentication tokens
- **Data Privacy**: Cached content belongs to specific user identity
- **Authorization**: API calls must use correct activeDid for proper authorization
### **Data Integrity Issues**
- **Cache Pollution**: Wrong user's data could leak between identities
- **Stale Authentication**: Old JWT tokens become invalid for new identity
- **Background Tasks**: Tasks running with wrong identity context
### **User Experience Problems**
```typescript
// PROBLEMATIC SCENARIO WITHOUT CHANGE NOTIFICATION:
// 1. User A schedules notification for "my offers"
// 2. User switches to User B
// 3. Plugin doesn't know about change
// 4. Plugin delivers User A's personal offer data to User B ❌
```
## Solution: Event-Based Change Notification
### **TimeSafari Host Application**
```typescript
// In PlatformServiceMixin.ts - CRITICAL PATTERN
async $updateActiveDid(newDid: string | null): Promise<void> {
// ... existing activeDid update logic ...
// MUST notify Daily Notification Plugin
await this.$notifyDailyNotificationService(newDid);
}
async $notifyDailyNotificationService(newActiveDid: string): Promise<void> {
const event = new CustomEvent('activeDidChanged', {
detail: { activeDid: newActiveDid }
});
document.dispatchEvent(event);
}
```
### **Plugin Side Implementation**
```typescript
// In Daily Notification Plugin - MANDATORY LISTENING
export class EnhancedDailyNotificationPlugin {
private currentActiveDid: string | null = null;
constructor() {
this.setupActiveDidChangeListener();
}
private setupActiveDidChangeListener(): void {
document.addEventListener('activeDidChanged', (event: CustomEvent) => {
this.handleActiveDidChange(event.detail.activeDid);
});
}
private async handleActiveDidChange(newActiveDid: string): Promise<void> {
if (newActiveDid !== this.currentActiveDid) {
logger.info(`[Plugin] ActiveDid changing from ${this.currentActiveDid} to ${newActiveDid}`);
// CRITICAL ACTIONS REQUIRED:
await this.clearCacheForNewIdentity();
await this.refreshAuthenticationForNewIdentity(newActiveDid);
await this.updateBackgroundTaskIdentity(newActiveDid);
this.currentActiveDid = newActiveDid;
}
}
async clearCacheForNewIdentity(): Promise<void> {
// Clear all cached content to prevent data leakage
await this.clearStoredContent();
await this.clearAuthenticationTokens();
}
async refreshAuthenticationForNewIdentity(activeDid: string): Promise<void> {
// Generate new JWT tokens with correct activeDid
const newJwt = await this.generateJWT(activeDid);
this.currentAuthToken = newJwt;
}
async updateBackgroundTaskIdentity(activeDid: string): Promise<void> {
// Update background tasks to use new identity
await this.pauseBackgroundTasks();
await this.configureBackgroundTasksForIdentity(activeDid);
await this.resumeBackgroundTasks();
}
}
```
## Implementation Requirements
### **Host Application Responsibilities**
1. **Event Dispatch**: Must dispatch `activeDidChanged` events
2. **Timing**: Dispatch immediately after updating active_identity table
3. **Reliability**: Event must reach all plugin listeners
### **Plugin Responsibilities**
1. **Event Listening**: Must listen for `activeDidChanged` events
2. **Cache Clearing**: Must clear all cached content for new identity
3. **Authentication Refresh**: Must generate new tokens with updated activeDid
4. **Background Task Update**: Must restart background tasks with new context
5. **Error Handling**: Must handle failures gracefully during identity transition
## Testing Requirements
### **Integration Tests**
```typescript
describe('ActiveDid Change Handling', () => {
it('should clear cache when activeDid changes', async () => {
// Set up initial identity
await plugin.setActiveDidFromHost('did:alice:123');
await plugin.cacheContentData({ /* Alice's data */ });
// Simulate identity change
const event = new CustomEvent('activeDidChanged', {
detail: { activeDid: 'did:bob:456' }
});
document.dispatchEvent(event);
// Verify cache is cleared
expect(await plugin.getCachedContent()).toBeNull();
});
it('should refresh authentication tokens', async () => {
// Set initial identity
const aliceToken = await plugin.generateJWT('did:alice:123');
// Change identity
document.dispatchEvent(new CustomEvent('activeDidChanged', {
detail: { activeDid: 'did:bob:456' }
}));
// Verify new token with correct identity
const bobToken = await plugin.getCurrentAuthToken();
expect(bobToken.payload.sub).toBe('did:bob:456');
});
it('should handle multiple rapid identity changes', async () => {
// Test rapid switching between identities
const identities = ['did:alice:123', 'did:bob:456', 'did:alice:123'];
for (const identity of identities) {
document.dispatchEvent(new CustomEvent('activeDidChanged', {
detail: { activeDid: identity }
}));
await new Promise(resolve => setTimeout(resolve, 100)); // Brief pause
}
// Ensure plugin ends up in correct state
expect(plugin.currentActiveDid).toBe('did:alice:123');
});
});
```
### **Edge Case Testing**
- **Network Failure**: Identity changes during network failures
- **Background Mode**: Identity changes when app is backgrounded
- **Rapid Switches**: Multiple identity changes in quick succession
- **Invalid activeDid**: Change to empty or invalid activeDid
## Platform-Specific Considerations
### **Android/Electron**
- Plugin can detect activeDid changes in background via database polling
- Backup mechanism if event-based notification fails
### **Web**
- Event-based notification is primary mechanism
- Fallback to periodic activeDid checking
### **iOS**
- Background tasks can check activeDid changes
- Event-based notification for foreground changes
## Performance Considerations
### **Change Detection Optimization**
- Debounce rapid identity changes
- Batch cache clearing operations
- Minimize background task restarts
### **Resource Cleanup**
- Clear authentication tokens immediately
- Clean up cached content efficiently
- Avoid memory leaks during transitions
---
**Status**: Critical requirement documented - Implementation required
**Next Steps**: Add activeDid change listeners to plugin implementation
**Security Impact**: HIGH - Prevents data leakage between user identities

22
doc/BACKGROUND_DATA_FETCHING_PLAN.md

@ -271,11 +271,15 @@ await plugin.configureDatabase({
const activeIdentity = await this.$getActiveIdentity(); const activeIdentity = await this.$getActiveIdentity();
await plugin.setActiveDidFromHost(activeIdentity.activeDid); await plugin.setActiveDidFromHost(activeIdentity.activeDid);
// CRITICAL: Set up activeDid change listener
plugin.onActiveDidChange(async (newActiveDid) => {
await plugin.clearCacheForNewIdentity();
await plugin.refreshAuthenticationForNewIdentity(newActiveDid);
logger.info(`[TimeSafari] ActiveDid changed to: ${newActiveDid}`);
});
// Enable automatic background lookup // Enable automatic background lookup
await plugin.enableAutoActiveDidMode(); await plugin.enableAutoActiveDidMode();
// Plugin can fetch content and cache independently
const results = await plugin.executeContentFetch(config);
``` ```
**Web: Host-Managed Database with Hybrid activeDid** **Web: Host-Managed Database with Hybrid activeDid**
@ -345,6 +349,11 @@ interface EnhancedDailyNotificationPlugin {
// TimeSafari Integration Methods // TimeSafari Integration Methods
initializeFromTimeSafari(): Promise<void>; initializeFromTimeSafari(): Promise<void>;
listenForActiveDidChanges(): Promise<void>; listenForActiveDidChanges(): Promise<void>;
// Critical: ActiveDid Change Handling
onActiveDidChange(callback: (newActiveDid: string) => Promise<void>): void;
clearCacheForNewIdentity(): Promise<void>;
refreshAuthenticationForNewIdentity(activeDid: string): Promise<void>;
} }
``` ```
@ -356,6 +365,11 @@ interface EnhancedDailyNotificationPlugin {
- **Implement** dual-mode activeDid access: - **Implement** dual-mode activeDid access:
- **Foreground**: Host provides activeDid via `setActiveDidFromHost()` - **Foreground**: Host provides activeDid via `setActiveDidFromHost()`
- **Background**: Plugin looks up activeDid via `refreshActiveDidFromDatabase()` - **Background**: Plugin looks up activeDid via `refreshActiveDidFromDatabase()`
- **Critical**: Plugin **MUST** know when activeDid changes for:
- **Event-Based Notification**: Listen for `activeDidChanged` events from TimeSafari
- **Cache Invalidation**: Clear cached content when user switches identity
- **Token Refresh**: Generate new JWT tokens with updated activeDid
- **Background Task Coordination**: Stop/restart tasks with new identity context
- **Coordinate** with TimeSafari's PlatformServiceMixin for identity changes - **Coordinate** with TimeSafari's PlatformServiceMixin for identity changes
## Migration & Testing Strategy ## Migration & Testing Strategy
@ -375,6 +389,8 @@ interface EnhancedDailyNotificationPlugin {
- Test `setActiveDidFromHost()` with TimeSafari PlatformServiceMixin - Test `setActiveDidFromHost()` with TimeSafari PlatformServiceMixin
- Test `refreshActiveDidFromDatabase()` with background tasks - Test `refreshActiveDidFromDatabase()` with background tasks
- Test `enableAutoActiveDidMode()` for automatic synchronization - Test `enableAutoActiveDidMode()` for automatic synchronization
- **Critical**: Test `onActiveDidChange()` listener with identity switches
- Test cache invalidation and token refresh during activeDid changes
- **Background testing** on real devices (doze mode, app backgrounding) - **Background testing** on real devices (doze mode, app backgrounding)
- **Authentication testing** with actual DID credentials from TimeSafari active_identity table - **Authentication testing** with actual DID credentials from TimeSafari active_identity table
- **Cross-platform testing** for Android/Electron (SQLite access) vs Web (host delegation) patterns - **Cross-platform testing** for Android/Electron (SQLite access) vs Web (host delegation) patterns

Loading…
Cancel
Save