blob: 7dd0fce1013f688993e2f54705448349b5e3c216 [file] [log] [blame]
Akron479994e2018-07-02 13:21:44 +02001/**
2 * The plugin system is based
3 * on registered widgets (iframes) from
4 * foreign services.
5 * The server component spawns new iframes and
6 * listens to them.
7 *
8 * @author Nils Diewald
9 */
10
Akrona6c32b92018-07-02 18:39:42 +020011define(["plugin/widget", "util"], function (widgetClass) {
Akron479994e2018-07-02 13:21:44 +020012 "use strict";
13
Akrona6c32b92018-07-02 18:39:42 +020014 // Contains all widgets to address with
15 // messages to them
16 var widgets = {};
17
Akrone8e2c952018-07-04 13:43:12 +020018 // This is a counter to limit acceptable incoming messages
19 // to a certain amount. For every message, this counter will
20 // be decreased (down to 0), for every second this will be
21 // increased (up to 100).
22 // Once a widget surpasses the limit, it will be killed
23 // and called suspicious.
24 var maxMessages = 100;
25 var limits = {};
26
27 // TODO:
28 // It may be useful to establish a watcher that pings
29 // all widgets every second to see if it is still alive.
30
Akron479994e2018-07-02 13:21:44 +020031 return {
32
33 /**
34 * Create new plugin management system
35 */
36 create : function () {
37 return Object.create(this)._init();
38 },
39
40 /*
41 * Initialize the plugin manager by establishing
42 * the global 'message' hook.
43 */
44 _init : function () {
45
Akrone8e2c952018-07-04 13:43:12 +020046 // TODO:
47 // It is better to establish the listener
48 // only in case there is a widget
49
Akron479994e2018-07-02 13:21:44 +020050 var that = this;
51 window.addEventListener("message", function (e) {
52 that._receiveMsg(e);
53 });
Akrona99315e2018-07-03 22:56:45 +020054
55 // Every second increase the limits of all registered widgets
56 var myTimer = setInterval(function () {
57 for (var i in limits) {
58 if (limits[i]++ >= maxMessages) {
59 limits[i] = maxMessages;
60 }
61 }
62 }, 1000);
Akron479994e2018-07-02 13:21:44 +020063 return this;
64 },
65
66 /**
Akrone8e2c952018-07-04 13:43:12 +020067 * Open a new widget as a child to a certain element
Akron479994e2018-07-02 13:21:44 +020068 */
69 addWidget : function (element, src) {
70
Akrona6c32b92018-07-02 18:39:42 +020071 // Create a unique random ID per widget
72 var id = 'id-' + this._randomID();
73
74 // Create a new widget
75 var widget = widgetClass.create(src, id);
76
77 // Store the widget based on the identifier
78 widgets[id] = widget;
Akrona99315e2018-07-03 22:56:45 +020079 limits[id] = maxMessages;
Akrona6c32b92018-07-02 18:39:42 +020080
81 // Open widget in frontend
82 element.appendChild(
83 widget.element()
84 );
Akron479994e2018-07-02 13:21:44 +020085 },
86
Akrone8e2c952018-07-04 13:43:12 +020087 // Receive a call from an embedded iframe.
88 // The handling needs to be very careful,
89 // as this can easily become a security nightmare.
Akron479994e2018-07-02 13:21:44 +020090 _receiveMsg : function (e) {
91 // Get event data
92 var d = e.data;
93
Akrona99315e2018-07-03 22:56:45 +020094 // If no data given - fail
95 // (probably check that it's an assoc array)
96 if (!d)
97 return;
98
99 // e.origin is probably set and okay - CHECK!
Akron479994e2018-07-02 13:21:44 +0200100
Akrona99315e2018-07-03 22:56:45 +0200101 // Get origin ID
102 var id = d["originID"];
103
104 // If no origin ID given - fail
105 if (!id)
106 return;
107
Akrona6c32b92018-07-02 18:39:42 +0200108 // Get the widget
Akrona99315e2018-07-03 22:56:45 +0200109 var widget = widgets[id];
Akrona6c32b92018-07-02 18:39:42 +0200110
111 // If the addressed widget does not exist - fail
112 if (!widget)
113 return;
114
Akrona99315e2018-07-03 22:56:45 +0200115 // Check for message limits
116 if (limits[id]-- < 0) {
Akrone8e2c952018-07-04 13:43:12 +0200117
118 // Kill widget
Akronc0a2da82018-07-04 15:27:37 +0200119 KorAP.log(0, 'Suspicious action by widget', widget.src);
Akrona99315e2018-07-03 22:56:45 +0200120 widget.shutdown();
121 delete limits[id];
122 delete widgets[id];
123 return;
124 };
Akrona6c32b92018-07-02 18:39:42 +0200125
Akron479994e2018-07-02 13:21:44 +0200126 // Resize the iframe
127 if (d.action === 'resize') {
Akrona6c32b92018-07-02 18:39:42 +0200128 widget.resize(d);
Akron479994e2018-07-02 13:21:44 +0200129 }
130
131 // Log message from iframe
132 else if (d.action === 'log') {
Akronc0a2da82018-07-04 15:27:37 +0200133 KorAP.log(d.code, d.msg, widget.src);
Akrona6c32b92018-07-02 18:39:42 +0200134 };
135
136 // TODO:
137 // Close
Akron479994e2018-07-02 13:21:44 +0200138 },
139
Akrona6c32b92018-07-02 18:39:42 +0200140 // Get a random identifier
141 _randomID : function () {
142 return randomID(20);
Akron479994e2018-07-02 13:21:44 +0200143 }
144 }
145});