xref: /plugin/diagrams/action/action.php (revision 317bdfc2bd4bf051cf5d349bd5d8d27dc2a0b6c5)
1<?php
2
3/**
4 * Action component of diagrams plugin
5 *
6 * FIXME move out all mediafile related stuff to a separate class and make it check the mode config
7 */
8class action_plugin_diagrams_action extends DokuWiki_Action_Plugin
9{
10
11    /**
12     * Registers a callback function for a given event
13     *
14     * @param \Doku_Event_Handler $controller
15     */
16    public function register(Doku_Event_Handler $controller)
17    {
18        $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'addJsinfo');
19        $controller->register_hook('MEDIAMANAGER_STARTED', 'AFTER', $this, 'addJsinfo');
20        $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'checkConf');
21        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxImages');
22        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxAcl');
23        $controller->register_hook('MEDIA_SENDFILE', 'BEFORE', $this, 'handleCSP');
24    }
25
26    /**
27     * Add data to JSINFO: full service URL and security token used for uploading
28     *
29     * @param Doku_Event $event
30     */
31    public function addJsinfo(Doku_Event $event)
32    {
33        global $JSINFO;
34        $JSINFO['sectok'] = getSecurityToken();
35        $JSINFO['plugins']['diagrams']['service_url'] = $this->getConf('service_url');
36    }
37
38    /**
39     * Check if DokuWiki is properly configured to handle SVG diagrams
40     *
41     * @param Doku_Event $event
42     */
43    public function checkConf(Doku_Event $event)
44    {
45        $mime = getMimeTypes();
46        if (!array_key_exists('svg', $mime) || $mime['svg'] !== 'image/svg+xml') {
47            msg($this->getLang('missingConfig'), -1);
48        }
49    }
50
51    /**
52     * Check all supplied images and return only editable diagrams
53     *
54     * @param Doku_Event $event
55     */
56    public function handleAjaxImages(Doku_Event $event)
57    {
58        if ($event->data !== 'plugin_diagrams_images') return;
59        $event->preventDefault();
60        $event->stopPropagation();
61
62        global $INPUT;
63        $images = $INPUT->arr('images');
64
65        echo json_encode($this->editableDiagrams($images));
66    }
67
68    /**
69     * Check ACL for supplied namespace
70     *
71     * @param Doku_Event $event
72     */
73    public function handleAjaxAcl(Doku_Event $event)
74    {
75        if ($event->data !== 'plugin_diagrams_acl') return;
76        $event->preventDefault();
77        $event->stopPropagation();
78
79        global $INPUT;
80        $ns = $INPUT->str('ns');
81
82        echo json_encode(auth_quickaclcheck($ns . ':*') >= AUTH_UPLOAD);
83    }
84
85    /**
86     * Add CSP img-src directive to allow loading images from data source
87     *
88     * @param Doku_Event $event
89     * @return void
90     */
91    public function handleCSP(Doku_Event $event)
92    {
93        if ($this->isDiagram($event->data['media'])) {
94            $event->data['csp']['img-src'] = "self data:";
95            $event->data['csp']['sandbox'] = "allow-popups allow-top-navigation allow-same-origin";
96        }
97    }
98
99
100    /**
101     * Return an array of diagrams editable by the current user
102     *
103     * @param array $images
104     * @return array
105     */
106    protected function editableDiagrams($images)
107    {
108        $editable = [];
109
110        foreach ($images as $image) {
111            if (auth_quickaclcheck(cleanId($image)) >= AUTH_UPLOAD && $this->isDiagram($image)) {
112                $editable[] = $image;
113            }
114        }
115
116        return $editable;
117    }
118
119    /**
120     * Return true if the image is recognized as our diagram
121     * based on content ('embed.diagrams.net' or 'draw.io')
122     *
123     * @param string $image image id
124     * @return bool
125     */
126    protected function isDiagram($image)
127    {
128        global $conf;
129        // strip nocache parameters from image
130        $image = explode('&', $image);
131        $image = $image[0];
132
133        // FIXME this should use mediaFN()
134        $file = init_path(
135            $conf['mediadir'] .
136            DIRECTORY_SEPARATOR .
137            preg_replace(['/:/'], [DIRECTORY_SEPARATOR], $image)
138        );
139
140        // FIXME replace with helper_plugin_diagrams::isDiagram()
141        if (!is_file($file)) return false;
142        $begin = file_get_contents($file, false, null, 0, 500);
143        $confServiceUrl = $this->getConf('service_url'); // like "https://diagrams.xyz.org/?embed=1&..."
144        $serviceHost = parse_url($confServiceUrl, PHP_URL_HOST); // Host-Portion of the Url, e.g. "diagrams.xyz.org"
145        return strpos($begin, 'embed.diagrams.net') || strpos($begin, 'draw.io') || strpos($begin, $serviceHost);
146    }
147}
148