Browse Source
- 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
2 changed files with 223 additions and 3 deletions
@ -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 |
Loading…
Reference in new issue