جعل عملية تنشيط المستخدمين متسقة عبر واجهات برمجة التطبيقات

Mustaq Ahmed
Joe Medley
Joe Medley

لمنع النصوص البرمجية الضارة من إساءة استخدام واجهات برمجة التطبيقات الحساسة، مثل النوافذ المنبثقة، وضع ملء الشاشة وغير ذلك، تتحكم المتصفحات في الوصول إلى واجهات برمجة التطبيقات هذه من خلال المستخدم التفعيل. تفعيل المستخدم هو حالة جلسة التصفُّح بالنسبة إلى إلى إجراءات المستخدم: علامة "نشطة" عادةً ما تشير إلى أن المستخدم يتفاعل حاليًا مع الصفحة، أو أكمل تفاعلاً منذ الصفحة التحميل. إيماءة المستخدم هي مصطلح شائع ولكنه مضلل للفكرة نفسها. بالنسبة على سبيل المثال، لا تؤدي إيماءة التمرير السريع أو التدوير من قبل المستخدم إلى تنشيط الصفحة، من وجهة نظر النص البرمجي، ليس تنشيطًا من قِبل المستخدم.

تُظهر المتصفحات الرئيسية حاليًا سلوكًا مختلفًا على نطاق واسع في ما يتعلق بكيفية تفعيل المستخدمين للتحكّم في واجهات برمجة التطبيقات التي تم تفعيل بوابة التفعيل عليها. في Chrome، استندت عملية التنفيذ على نموذج قائم على رموز مميزة يبدو معقدًا للغاية بحيث لا يمكن تحديد السلوك عبر جميع واجهات برمجة التطبيقات المحظورة على عملية التفعيل على سبيل المثال، كان Chrome السماح بالوصول غير المكتمل إلى واجهات برمجة التطبيقات المحمية ببوابة التفعيل من خلال postMessage() و setTimeout() مكالمات ولم يتم تفعيل تفاعل المستخدم متوافقة مع الوعود XHR، التفاعل مع لوحة الألعاب، وما إلى ذلك. لاحظ أن بعضًا من هذه هي أخطاء شائعة ولكنها طويلة الأمد.

في الإصدار 72، يوفر Chrome الإصدار 2 من تفعيل المستخدم الذي يجعل المستخدم اكتمل مدى توفُّر التفعيل لجميع واجهات برمجة التطبيقات المحظورة على عملية التفعيل. يؤدي هذا الإجراء إلى حلّ التناقضات المذكورة أعلاه (وقليلة أخرى، مثل MessageChannels)، التي نتوقّع أن تساهم في تسهيل تجربة الويب والتطوير حول تنشيط المستخدم. علاوة على ذلك، توفر طريقة التنفيذ الجديدة في التنفيذ المرجعي المواصفات الجديدة يهدف إلى تجميع كل المتصفحات معًا على المدى الطويل.

كيف يعمل الإصدار 2 من تفعيل المستخدم؟

تحتفظ واجهة برمجة التطبيقات الجديدة بحالة تفعيل المستخدم الثنائية في كل عنصر من كائنات window. في التسلسل الهرمي للإطارات: وحدة بت ثابتة لحالة تنشيط المستخدم السابقة (إذا وقد شهد الإطار عملية تنشيط من قِبل المستخدم)، كما أنّ هناك بعض البيانات المؤقتة للحالة الحالية (إذا رصد أحد الإطارات عملية تفعيل من جانب المستخدم خلال ثانية تقريبًا) البت اللاصق لا تتم إعادة ضبطه أبدًا أثناء عمر الإطار بعد ضبطه. البت العابر يتم تعيينها على كل تفاعل للمستخدم، وتتم إعادة ضبطها إما بعد انتهاء الصلاحية فاصلة (حوالي ثانية) أو من خلال طلب بيانات من واجهة برمجة تطبيقات تحتاج إلى تفعيل (مثال: window.open()).

تجدر الإشارة إلى أنّ مختلف واجهات برمجة التطبيقات المرتبطة ببوابة تفعيل تعتمد على تفعيل المستخدِم بطرق مختلفة الطرق؛ لن تغيّر واجهة برمجة التطبيقات الجديدة أيًا من هذه السلوكيات الخاصة بواجهة برمجة التطبيقات. مثلاً: يُسمح بنافذة منبثقة واحدة فقط لكل عملية تفعيل للمستخدم بسبب استهلاك window.open(). طلب تفعيل المستخدم كما كان من قبل، فإن Navigator.prototype.vibrate() يواصل أن تكون فعالة إذا كان هناك إطار (أو أي من إطاراته الفرعية) قد رأى إجراء مستخدم، وهكذا

ما الذي سيتغيّر؟

  • الإصدار 2 من تفعيل المستخدم يضفي طابعًا رسميًا على مفهوم مستوى ظهور تفعيل المستخدم عبر حدود الإطارات: يصبح تفاعل المستخدم مع إطار معين الآن تفعيل جميع الإطارات التي تحتوي على (وتلك الإطارات فقط) بغض النظر عن المصدر. (في الإصدار Chrome 72، لدينا حل بديل مؤقت لتوسيع مستوى الرؤية لجميع الإطارات ذات المصدر نفسه. سنزيل هذا الحل البديل بمجرد الحصول على طريقة تمرير تفعيل المستخدم صراحةً إلى الإطارات الفرعية).
  • عندما يتم استدعاء واجهة برمجة تطبيقات ببوابة تفعيل من إطار نشط ولكن من خارج رمز معالج الأحداث، فإنه يعمل ما دام تفعيل المستخدم الحالة "نشطة" (على سبيل المثال، لم تنتهِ صلاحيتها ولم يتم استهلاكها). قبل المستخدم التفعيل الإصدار 2، فسيفشل بدون شروط.
  • تفاعلات المستخدم المتعددة غير المستخدمة خلال عمليات دمج الفاصل الزمني لانتهاء الصلاحية في عملية تفعيل واحدة تقابل التفاعل الأخير.

أمثلة على الاتساق في واجهات برمجة التطبيقات المحظورة على عملية التفعيل

في ما يلي مثالان على النوافذ المنبثقة (التي يتم فتحها باستخدام window.open()) التي عرض كيف يؤدي تفعيل User Activation v2 إلى سلوك واجهات برمجة التطبيقات المحظورة على عملية التفعيل متسقة.

سلسلة مكالمات setTimeout()

هذا المثال مأخوذ من العرض التوضيحي لـ setTimeout(). إذا حاول معالج click فتح نافذة منبثقة خلال ثانية، من المتوقّع أن للنجاح بغض النظر عن طريقة "إنشاء" التأخير. يتوافق الإصدار 2 من تفعيل المستخدم هذا التوقع، لذلك يفتح كل من معالِجات الأحداث التالية نافذة منبثقة على click (مع مهلة تبلغ 100 ملي ثانية):

function popupAfter100ms() {
  setTimeout(callWindowOpen, 100);
}

function asyncPopupAfter100ms() {
  setTimeout(popupAfter100ms, 0);
}

someButton.addEventListener('click', popupAfter100ms);
someButton.addEventListener('click', asyncPopupAfter100ms);

بدون تفعيل User Activation v2، يتعذّر تشغيل معالج الحدث الثاني في جميع المتصفّحات التي اختباره. (حتى تعذّرت المحاولة الأولى) في بعض الحالات).

مكالمات "postMessage()" عبر النطاقات

إليك مثال من العرض التوضيحي لـ postMessage(). لنفترض أنّ معالج click في إطار فرعي من مصادر متعددة يرسل رسالتَين مباشرةً. إلى الإطار الأصلي. يجب أن يتمكن الإطار الأصلي من فتح نافذة منبثقة عند تلقي أي من هاتين الرسالتين (وليس كلاهما):

// Parent frame code
window.addEventListener('message', e => {
  if (e.data === 'open_popup' && e.origin === child_origin)
    window.open('about:blank');
});

// Child frame code:
someButton.addEventListener('click', () => {
  parent.postMessage('hi_there', parent_origin);
  parent.postMessage('open_popup', parent_origin);
});

بدون الإصدار 2 من تفعيل المستخدِم، لا يمكن للإطار الرئيسي فتح نافذة منبثقة عند الاستلام. الرسالة الثانية. حتى الرسالة الأولى تخفق إذا كانت "متسلسلة" إلى آخر إطار من مصادر متعددة (بمعنى آخر، إذا أعاد المستلِم الأول توجيه الرسالة) إلى آخر).

وتعمل هذه الاستراتيجية مع الإصدار 2 من User Activation، سواءً بالصيغة الأصلية أو والسلسلة.