/** * openR&D PIN delivery. Deploy this as a web app under v.kondus@sci.sumdu.edu.ua: * Execute as: Me; access: Anyone. Before deploying, set script property * OPENRD_MAIL_SECRET to the same random secret stored in the site's * GMAIL_SCRIPT_SECRET environment variable. Never put that secret in this file. */ function doPost(e) { try { const request = JSON.parse(e.postData.contents); if (typeof request.message !== 'string' || typeof request.signature !== 'string') return result_(false); const secret = PropertiesService.getScriptProperties().getProperty('OPENRD_MAIL_SECRET'); if (!secret || secret.length < 32) return result_(false); const expected = hex_(Utilities.computeHmacSha256Signature(request.message, secret, Utilities.Charset.UTF_8)); if (!equal_(expected, request.signature.toLowerCase())) return result_(false); const data = JSON.parse(request.message); if (!Number.isFinite(data.ts) || Math.abs(Date.now() - data.ts) > 120000) return result_(false); if (typeof data.nonce !== 'string' || !/^[0-9a-f-]{36}$/.test(data.nonce)) return result_(false); if (data.purpose !== 'openrd-pin-v1' && data.purpose !== 'openrd-pin-ping-v1') return result_(false); const lock = LockService.getScriptLock(); if (!lock.tryLock(5000)) return result_(false); try { const cache = CacheService.getScriptCache(); if (cache.get(data.nonce)) return result_(false); cache.put(data.nonce, '1', 300); } finally { lock.releaseLock(); } if (data.purpose === 'openrd-pin-ping-v1') return result_(true); if (typeof data.name !== 'string' || data.name.length < 2 || data.name.length > 100) return result_(false); if (typeof data.email !== 'string' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email) || data.email.length > 254) return result_(false); if (typeof data.pin !== 'string' || !/^\d{4}$/.test(data.pin)) return result_(false); const parts = data.name.trim().split(/\s+/); const greeting = parts.length >= 3 ? parts.slice(1, 3).join(' ') : parts.length === 2 ? parts[1] : parts[0]; const body = 'Вітаємо, ' + greeting + '!\n\n' + 'Ваш PIN для входу в кабінет openR&D: ' + data.pin + '.\n' + 'Відкрийте https://www.openrd.svn-pumps.top/, натисніть «Кабінет» і введіть PIN.\n' + 'Будь ласка, не передавайте його іншим.'; MailApp.sendEmail(data.email, 'Ваш PIN для входу в openR&D', body); return result_(true); } catch (_) { return result_(false); } } function result_(ok) { return ContentService.createTextOutput(JSON.stringify({ ok: ok })).setMimeType(ContentService.MimeType.JSON); } function hex_(bytes) { return bytes.map(function (byte) { return ('0' + (byte & 255).toString(16)).slice(-2); }).join(''); } function equal_(a, b) { if (a.length !== b.length) return false; let difference = 0; for (let i = 0; i < a.length; i++) difference |= a.charCodeAt(i) ^ b.charCodeAt(i); return difference === 0; }