تعارض مع حل Quantcast RGPD "choice" و ember.js

مرحبًا،
هذه مشكلة محددة جدًا، لكن تأثيرها قد يمتد إلى ما هو أبعد من هذه الحالة المحددة، لذا لدي سؤال بخصوصها.

(أيضًا، أعتذر عن لغتي الإنجليزية؛ أنا فرنسي، لذا لست متحدثًا أصليًا على الإطلاق…)

ولكن أولًا، دعني أشرح السياق.
أستخدم منصة Discourse منذ فترة لإدارة منتدى فرنسي حول راسبيري باي (forum.raspberry-pi.fr). يستخدم هذا المنتدى نظام إدارة الإعلانات (themoneytizer). وكما تعلمون على الأرجح، فإن القوانين الأوروبية تلزمنا بتنفيذ لائحة حماية البيانات العامة (RGPD) لحماية خصوصية المستخدمين. والجهة الفاعلة الرئيسية (على الأقل في فرنسا) في مجال موافقة RGPD هي شركة Quantcast وحلها المسمى “Choice”.

لذا، كنت أستخدم حل Quantcast منذ فترة طويلة دون أي مشاكل، حتى لاحظت مؤخرًا أن زر “قبول الكل” لا يعمل بشكل صحيح بعد الآن. عند النقر عليه، لا يحدث شيء، وعند فحص وحدة التحكم للمطورين (dev console) ظهر هذا الخطأ: “Uncaught TypeError: can’t define property “status”: Function is not extensible”.

ما يحدث (على الأقل حسب فهمي):
ثقوا بي عندما أقول إن الأمر استغرق مني وقتًا طويلاً جدًا جدًا لإيجاد مصدر المشكلة. يبدو أن مكتبة ember.js (التي لست على دراية جيدة بها) تقوم بتمديد بعض الكائنات الأصلية في JavaScript، مثل Array و String و Function. وبسبب سبب ما، يبدو أنها تمنع أيضًا تمديد هذه الكائنات بطريقة ما (لم أفهم هذا الجزء بالكامل بعد).

من جانبه، يحاول حل Quantcast، ربما في الدالة FunctionAcceptAll (مما يفسر أن الخطأ يحدث فقط عند النقر على زر قبول الكل أو رفض الكل)، تمديد كائن، أفترض أنه مصفوفة، وقد تغير سلوكه الطبيعي بسبب ember.js.

بعد الكثير من البحث لفهم هذه المشكلة، اكتشفت أيضًا أنه من الممكن تعديل سلوك Ember.js لعدم تمديد بروتوتيبات JavaScript، كما هو موضح في هذه الصفحة: https://guides.emberjs.com/release/configuring-ember/disabling-prototype-extensions/.

أجريت بعض الاختبارات، وتختفي المشكلة إذا أضفت السطر window.EmberENV.EXTEND_PROTOTYPES = {String: true, Array: false}; في الملف _ember_jquery-189e46ebcb33594b835e782fd1ce916ec750bc0cf980ebc4fb7796649161a18d.js بعد السطر window.EmberENV.FORCE_JQUERY = true;.

لأولئك منكم الذين يرغبون في تجربة ذلك، يمكنكم زيارة صفحة /tst/index.html على المنتدى (قد تحتاجون إلى عنوان IP أوروبي لبدء تشغيل السكربت، ليس لدي أي فكرة عن السبب).
الآن، أعتقد أن لديكم جميع المعلومات التي يمكنني تقديمها.

إذن، ها هو سؤالي الآن.
على الرغم من أن هذه مشكلة محددة جدًا، إلا أن لائحة RGPD أصبحت أكثر حضورًا في أوروبا حاليًا، ولن يصبح الأمر أسهل في المستقبل.
تتمتع شركة Quantcast بموقف شبه احتكاري، على الأقل بالنسبة للجهات التي لا تستطيع دفع مئات الدولارات لتنفيذ RGPD. تمنع هذه المشكلة أي استخدام لـ Quantcast، وبالتالي أي استخدام للإعلانات على Discourse في أوروبا، وهو ما يبدو لي مشكلة كبيرة.
أيضًا، حتى لو اكتشفت هذه المشكلة باستخدام Quantcast فقط، فقد تحدث مثل هذه الأخطاء مع العديد من السكربتات الخارجية التي يجب تضمينها للإعلانات أو لأغراض أخرى، والتي لا نملك أي سيطرة عليها، وتعتمد على السلوك “العادي” لـ JavaScript لكائنات Array و String و Function.

لا أعرف كود Discourse بما يكفي، لذا أوجه إليكم السؤال: هل الخصائص التي أضافتها ember.js على كائنات Array و String و Function (انظر الرابط السابق) مستخدمة في Discourse أم لا؟ إذا لم تكن مستخدمة، ربما يجب علينا النظر في تعطيل تمديد البروتوتيبات من ember.js لمنع آثار جانبية مثل هذه؟

آمل أن يتمكن شخص ما من تزويدي بمعلومات حول هذا الأمر،
شكرًا لكم

هذا غير مدعوم حاليًا، حيث نعتمد على الامتدادات. ربما في إصدار مستقبلي لن نحتاج إليها. يمكن لـ @eviltrout تقديم المزيد من التوضيحات.

لست متأكدًا مما يجب فعله هنا، لكن أعتقد أننا يجب أن يكون لدينا حل بديل. أنا مندهش من أن هذا يكسر RGPD، ربما نفتح تذكرة مع Quantcast لمناقشة الأمر ووضع رابط هنا؟

كيف تضيف السكريبتات المطلوبة لـ Quantcast؟ هل تضيفها عبر وسم <script> مع رابط خارجي (src) مثل هذا:

<script src="foo"></script>

أم تضيفها مضمنة (inline) مثل هذا؟

<script>
  alert("Hello World!");
</script>

مرحبًا،
شكرًا لاستجاباتكم.

@sam لقد فتحت تذكرة مع Quantcast في اليوم الذي أنشأت فيه هذا الموضوع، وقد ردوا عليّ اليوم. يبدو أنهم يفحصون المشكلة حاليًا، وآمل أن يجدوا حلًا لها. أعتقد أن هذا إصلاح بسيط نسبيًا بالنسبة لهم، حيث أن زر “قبول الاختيار” يعمل بشكل صحيح. لنأمل أن يكتشفوا أن Discourse وember.js يُستخدمان بشكل كافٍ لاستحقاق إصلاح مخصص.

@Johani في الواقع، لا أضيف سكريبتات Quantcast بنفسي، بل يوفر TheMoneyTizer سكريبتًا يقوم بذلك نيابةً عني (بالإضافة إلى البحث عن أحداث tcf2 وما إلى ذلك). يمكنك الاطلاع على هذا السكريبت هنا إذا أردت.

يبدو أن هذا السكريبت يضيف عنصر جديدًا قبل أول سكريبت في الصفحة. قد لا أكون متأكدًا تمامًا، لكنني أعتقد بشدة أنني رأيت هذا السكريبت بالضبط في بعض أمثلة وثائق Quantcast، لذا أفترض أنه سكريبت شائع الاستخدام لدمج Quantcast Choice.

شكرًا مرة أخرى على وقتكم.

لا أرى أننا سنقوم بإزالة نماذج الكائنات الخاصة بالمصفوفات (array prototypes) بأمان في أي وقت قريب. لقد كانت هذه النماذج غير ضارة على مر السنين وتضيف الكثير من الراحة.

ربما يمكنك التواصل مع شركة Quantcast للحصول على نسخة من السكربتات لا تعتمد على نماذج المصفوفات؟

مرحباً بالجميع،
لدي بعض المعلومات الجديدة لكم وقد وجدت حلاً لهذه المشكلة.

لذلك، اليوم قمت بالبحث مرة أخرى في هذا الخطأ وأعتقد أنني وجدت المزيد من المعلومات.

من خلال النظر في الملف cmp2ui-fr.js الخاص بـ Quantcast، تمكنت من تحديد مكان حدوث الخطأ، وهو في هذه الدالة (لدينا فقط النسخة المصغرة):

function(t){for(var n in t){t[n].status=e;}}

كما ترون، تستخدم هذه الدالة حلقة for..in، والمتغير t هو مصفوفة. لقد شرحنا ذلك سابقاً، حيث يقوم Ember.js بتوسيع المصفوفة الأصلية في JavaScript. ويبدو أن أحد التعديلات هو إضافة إدخال _super.

يشير إدخال _super إلى دالة ROOT()، والتي تبدو أنها تشير إلى _utils.ROOT في Ember.js (ربما يبدو هذا مألوفاً لبعضكم، لكن ليس لي ^^). هذه الدالة ROOT() غير قابلة للتوسيع.

يبدو أن خاصية _super تعتبر enumerable، مما يعني أنه عند استخدام حلقة for..in على مصفوفة، يُعتبر إدخال _super إدخالاً “عادياً” (على عكس، على سبيل المثال، values، bind، valueOf، أي جميع دوال كائن المصفوفة).

أعتقد أن هذا خطأ في Ember.js وليس سلوكاً مرغوباً فيه.

لذلك، تمكنت من جعل الخطأ قابلاً للتكرار بسهولة. للقيام بذلك، قم بإنشاء مصفوفة من الكائنات، مثل هذا:

var objs = [{'key':'val'},{'key':'val'}];

ثم، قم بإنشاء دالة باستخدام الوضع الصارم، تتكرر فوق مصفوفة وتعيين خاصية جديدة لكل إدخال:

var tst_func = function (objs){'use strict';for(var i in objs){objs[i].newproperty = true }};

أخيراً، قم فقط باستدعاء هذه الدالة على مصفوفة الكائنات:

tst_func(objs);

يجب أن تحصل على خطأ Uncaught TypeError: can't define property "newproperty": Function is not extensible.

النظر في هذا يجعلني أعتقد أن الخطأ موجود بالفعل في الميدان وليس محدداً لـ Quantcast. بشكل أساسي، أي شخص يحاول استخدام for..in يعرض نفسه لسلوك غير متناسق أو خطأ حرج.

بالنسبة لي، الأمر لا يتعلق بـ Discourse أو Quantcast، بل بوضوح بـ Ember.js. ومع ذلك، لا يغير ذلك حقيقة أننا بحاجة إلى إيجاد حل لها طالما لم يتم إصلاحها في Ember.js ^^.

الخبر السار هو أنني أعتقد أنني وجدت طريقة لإصلاح هذا.

إحدى الطرق للقيام بذلك هي استخدام سطر if (!objs.hasOwnProperty(i)) {continue}; في كل حلقة for..in (وربما أيضاً each، for of، إلخ). هذا لا يغير السلوك الغريب للمصفوفة _super، لكنه يمنع الوصول إليه محلياً. وهذا يعني بالطبع أن هذا لا يعمل مع أي سكريبت خارجي لا نسيطر عليه، مثل حالة استخدام Quantcast الخاصة بي.

طريقة أخرى، والتي أعتقد أنها المسار الصحيح، هي تعديل نموذج المصفوفة في JavaScript (لذلك نحن في الأساس نلغي تجاوز Ember.js الخاص به ^^) لجعل _super غير قابل للعد. للقيام بذلك، يجب علينا تشغيل سطر JS هذا بعد استدعاء Ember.js وتقييمه:

//Make _super not enumerable to prevent bug between emberjs and for..in
Object.defineProperty(Array.prototype, '_super', {'enumerable': false});

الطريقة الثانية تسمح بالاستخدام المباشر لـ _super، كما كان من المفترض، وتمنع ظهوره في الحلقات. ومع ذلك، لا يمكنني ضمان عدم استخدام هذا السلوك الغريب من قبل أي دالة داخلية في Ember.js أو إضافة خارجية.

بالنظر إلى الملف _ember_jquery-189e46ebcb33594b835e782fd1ce916ec750bc0cf980ebc4fb7796649161a18d.js، رأيت بعض الأسطر المحددة لـ Discourse، مثل:

var ALIASES = {
    "ember-addons/ember-computed-decorators":
      "discourse-common/utils/decorators",
    "discourse/lib/raw-templates": "discourse-common/lib/raw-templates",
    "preload-store": "discourse/lib/preload-store",
    "fixtures/user_fixtures": "discourse/tests/fixtures/user-fixtures",
  };
  var ALIAS_PREPEND = {
    fixtures: "discourse/tests/",
    helpers: "discourse/tests/",
  };

ربما يمكننا إضافة سطر Object.defineProperty(Array.prototype, '_super', {'enumerable': false}); هنا؟

بالنسبة لي، قمت حالياً بإصلاح الخطأ بإضافة الأسطر:
//Make _super not enumerable to prevent bug between emberjs and for..in
Object.defineProperty(Array.prototype, ‘_super’, {‘enumerable’: false});

قبل استدعاء سكريبت Quantcast choice.js.

أعتقد أن شخصاً ما يمكنه إصلاح الخطأ محلياً بإنشاء ملف ‘fix_ember.js’ يحتوي على هذين السطرين، وخدمته بشكل ثابت من خلال الوكيل العكسي (على سبيل المثال Nginx)، وإضافة سطر <script src="/fix_emmber.js"></script> في تذييل الموضوع باستخدام التخصيص. لا يعمل كتابة السكريبت مباشرة بدلاً من إنشاء رابط بسبب استخراج السكريبت في Discourse (انظر Custom javascript in <head> disappear).

آمل أن يساعد هذا الموضوع الآخرين. سأفتح تذكرة في Ember.js غداً، لمعرفة ما إذا كان هذا خطأ أو سلوكاً غريباً جداً ولكنه متعمد.

سأبقيكم على اطلاع لمعرفة ما إذا كان علينا تضمين إصلاح في Discourse.

ملاحظة: شكراً جزيلاً لـ Angus Croll من https://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/، ساعدني منشوره كثيراً!

شكرًا جزيلاً لك @OsaAjani على اهتمامك بهذا الموضوع. لدينا نفس المشكلة تمامًا مع خيار Quantcast في منتدى Discourse الخاص بنا، وقد علّقنا عند الإصدار 12 (وهو آخر إصدار لا يسبب خطأً).

أحدث إصدار هو 23، ونود بشدة استخدام أحدث إصدار.

نتطلع إلى سماع كيفية حل هذه المشكلة في أقرب وقت ممكن.

مرحبًا @Terrapop، يسعدني أن هذا الموضوع قد يساعدك. حتى الآن، لم أحصل على أي رد مطلقًا بشأن المشكلة التي فتحتها في مستودع ember.js ([Bug] Property "_super" is enumerable on Array, creating conflicts with external libs (ex : Quantcast Choice RGPD) · Issue #19289 · emberjs/ember.js · GitHub). كما لم أحصل على أي رد من Quantcast أيضًا.

ولكن الخبر الجيد هو أنني استخدمت الإصلاح الموضح في رسالتي السابقة، وهو إنشاء ملف fix_ember.js يحتوي على الكود التالي:

Object.defineProperty(Array.prototype, '_super', {'enumerable': false});

ثم إضافة السطر التالي:

<script defer src="/fix_emmber.js"></script>

في تذييل القالب باستخدام خيارات التخصيص من لوحة الإدارة.

هذا الحل يحل المشكلة بالفعل، وحتى الآن لم ألاحظ أي آثار جانبية. لذا، أعتقد أنه يمكنك استخدام هذا الإصلاح بثقة والانتقال إلى الإصدار v23 من Quantcast.

أضفنا السطر قبل تحميل choice.js. يبدو أن هذا يعمل بشكل جيد أيضًا.

بالنسبة للحل الآخر: لا نملك وكيل عكسي أمام Discourse، لذا غير متأكدين من كيفية إنشاء ملف fix_ember.js بالطريقة الصحيحة. هل هذا ممكن حتى داخل Docker؟ هل لديك أي اقتراح؟

حسناً، إذا تمكنت من تحميله قبل choice.js، فهذا أفضل!

نعم، يعمل. لا يمكننا أن نشكركم بما يكفي، لقد حككنا رؤوسنا لأيام بشأن هذا الأمر لأننا لم نتمكن من العثور على المشكلة. أجرينا 20 رسالة بريد إلكتروني متبادلة مع Quantcast، ولم يتمكنوا هم أيضًا من تحديد المشكلة.

حسناً، إذا كان لديك قناة اتصال جيدة مع كوانت كاست، ربما يمكنك توجيههم إلى هذا المنشور حتى يتمكنوا من إصلاحه. لقد حاولت، لكن بما أنني لست عميلاً فعلياً لديهم، لم يقدم لي الدعم سوى استجابات قليلة.

سأفعل. نقطة جيدة.