From 1939b560d95dcae726ae37f6e952e9ab77fb1bc7 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Thu, 2 Oct 2025 09:05:08 +0000 Subject: [PATCH] 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. --- doc/ACTIVE_DID_CHANGE_REQUIREMENTS.md | 204 ++++++++++++++++++++++++++ doc/BACKGROUND_DATA_FETCHING_PLAN.md | 22 ++- 2 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 doc/ACTIVE_DID_CHANGE_REQUIREMENTS.md diff --git a/doc/ACTIVE_DID_CHANGE_REQUIREMENTS.md b/doc/ACTIVE_DID_CHANGE_REQUIREMENTS.md new file mode 100644 index 0000000..2d33a75 --- /dev/null +++ b/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 { + // ... existing activeDid update logic ... + + // MUST notify Daily Notification Plugin + await this.$notifyDailyNotificationService(newDid); +} + +async $notifyDailyNotificationService(newActiveDid: string): Promise { + 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 { + 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 { + // Clear all cached content to prevent data leakage + await this.clearStoredContent(); + await this.clearAuthenticationTokens(); + } + + async refreshAuthenticationForNewIdentity(activeDid: string): Promise { + // Generate new JWT tokens with correct activeDid + const newJwt = await this.generateJWT(activeDid); + this.currentAuthToken = newJwt; + } + + async updateBackgroundTaskIdentity(activeDid: string): Promise { + // 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 diff --git a/doc/BACKGROUND_DATA_FETCHING_PLAN.md b/doc/BACKGROUND_DATA_FETCHING_PLAN.md index 3ca15aa..939b0c9 100644 --- a/doc/BACKGROUND_DATA_FETCHING_PLAN.md +++ b/doc/BACKGROUND_DATA_FETCHING_PLAN.md @@ -271,11 +271,15 @@ await plugin.configureDatabase({ const activeIdentity = await this.$getActiveIdentity(); 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 await plugin.enableAutoActiveDidMode(); - -// Plugin can fetch content and cache independently -const results = await plugin.executeContentFetch(config); ``` **Web: Host-Managed Database with Hybrid activeDid** @@ -345,6 +349,11 @@ interface EnhancedDailyNotificationPlugin { // TimeSafari Integration Methods initializeFromTimeSafari(): Promise; listenForActiveDidChanges(): Promise; + + // Critical: ActiveDid Change Handling + onActiveDidChange(callback: (newActiveDid: string) => Promise): void; + clearCacheForNewIdentity(): Promise; + refreshAuthenticationForNewIdentity(activeDid: string): Promise; } ``` @@ -356,6 +365,11 @@ interface EnhancedDailyNotificationPlugin { - **Implement** dual-mode activeDid access: - **Foreground**: Host provides activeDid via `setActiveDidFromHost()` - **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 ## Migration & Testing Strategy @@ -375,6 +389,8 @@ interface EnhancedDailyNotificationPlugin { - Test `setActiveDidFromHost()` with TimeSafari PlatformServiceMixin - Test `refreshActiveDidFromDatabase()` with background tasks - 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) - **Authentication testing** with actual DID credentials from TimeSafari active_identity table - **Cross-platform testing** for Android/Electron (SQLite access) vs Web (host delegation) patterns