| … | … | @@ -8,7 +8,7 @@ |
| 8 | 8 | "purpose": "Seeding pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso", |
| 9 | 9 | "command": "pear seed pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso .", |
| 10 | 10 | "persistent": true, |
| 11 | "latest_version": "11447", | |
| 11 | "latest_version": "11451", | |
| 12 | 12 | "last_deployed": "2026-01-27", |
| 13 | 13 | "features": "Phase 2 COMPLETE: Auth + Encryption + Validation + Rate Limiting + CORS + Signed Invites + Password Unlock UI ✅" |
| 14 | 14 | }, |
| … | … | @@ -102,10 +102,18 @@ function verifyToken(req) { |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | 104 | // Use constant-time comparison to prevent timing attacks |
| 105 | return crypto.timingSafeEqual( | |
| 106 | Buffer.from(token), | |
| 107 | Buffer.from(storedToken) | |
| 108 | ) | |
| 105 | // Note: crypto.timingSafeEqual doesn't exist in Bare runtime | |
| 106 | // Implement manual constant-time comparison | |
| 107 | if (token.length !== storedToken.length) { | |
| 108 | return false | |
| 109 | } | |
| 110 | ||
| 111 | let diff = 0 | |
| 112 | for (let i = 0; i < token.length; i++) { | |
| 113 | diff |= token.charCodeAt(i) ^ storedToken.charCodeAt(i) | |
| 114 | } | |
| 115 | ||
| 116 | return diff === 0 | |
| 109 | 117 | } |
| 110 | 118 | |
| 111 | 119 | /** |