xref: /plugin/twofactor/Manager.php (revision a386a536946c52f862186062d92ef1b00c31406b)
1<?php
2
3namespace dokuwiki\plugin\twofactor;
4
5use dokuwiki\Extension\Plugin;
6
7/**
8 * Manages the child plugins etc.
9 */
10class Manager extends Plugin
11{
12    /** @var Manager */
13    protected static $instance;
14
15    /** @var bool */
16    protected $ready = false;
17
18    /** @var string[] */
19    protected $classes = [];
20
21    /** @var Provider[] */
22    protected $providers;
23
24    /**
25     * Constructor
26     */
27    protected function __construct()
28    {
29        $this->classes = $this->getProviderClasses();
30
31        $attribute = plugin_load('helper', 'attribute');
32        if ($attribute === null) {
33            msg('The attribute plugin is not available, 2fa disabled', -1);
34        }
35
36        if (!count($this->classes)) {
37            msg('No suitable 2fa providers found, 2fa disabled', -1);
38            return;
39        }
40
41        $this->ready = true;
42    }
43
44    /**
45     * Get the instance of this singleton
46     *
47     * @return Manager
48     */
49    public static function getInstance()
50    {
51        if (self::$instance === null) {
52            self::$instance = new Manager();
53        }
54        return self::$instance;
55    }
56
57    /**
58     * Is the plugin ready to be used?
59     *
60     * @return bool
61     */
62    public function isReady()
63    {
64        return $this->ready;
65    }
66
67    /**
68     * @return bool|void
69     */
70    public function isRequired()
71    {
72        $set = $this->getConf('optinout');
73        if ($set === 'mandatory') {
74            return true;
75        }
76        // FIXME handle other options:
77        // when optout, return true unless user opted out
78
79        return false;
80    }
81
82    /**
83     * Convenience method to get current user
84     *
85     * @return string
86     */
87    public function getUser()
88    {
89        global $INPUT;
90        return $INPUT->server->str('REMOTE_USER');
91    }
92
93    /**
94     * Get all available providers
95     *
96     * @return Provider[]
97     */
98    public function getAllProviders()
99    {
100        $user = $this->getUser();
101        if (!$user) {
102            throw new \RuntimeException('2fa Providers instantiated before user available');
103        }
104
105        if ($this->providers === null) {
106            $this->providers = [];
107            foreach ($this->classes as $plugin => $class) {
108                $this->providers[$plugin] = new $class($user);
109            }
110        }
111
112        return $this->providers;
113    }
114
115    /**
116     * Get all providers that have been already set up by the user
117     *
118     * The first in the list is their default choice
119     *
120     * @return Provider[]
121     */
122    public function getUserProviders()
123    {
124        $list = $this->getAllProviders();
125        $list = array_filter($list, function ($provider) {
126            return $provider->isConfigured();
127        });
128
129        // FIXME handle default provider
130        return $list;
131    }
132
133    /**
134     * Get the instance of the given provider
135     *
136     * @param string $providerID
137     * @return Provider
138     */
139    public function getUserProvider($providerID)
140    {
141        $providers = $this->getUserProviders();
142        if (isset($providers[$providerID])) return $providers[$providerID];
143        throw new \RuntimeException('Uncofigured provider requested');
144    }
145
146    /**
147     * Find all available provider classes
148     *
149     * @return string[];
150     */
151    protected function getProviderClasses()
152    {
153        // FIXME this relies on naming alone, we might want to use an action for registering
154        $plugins = plugin_list('helper');
155        $plugins = array_filter($plugins, function ($plugin) {
156            return $plugin !== 'twofactor' && substr($plugin, 0, 9) === 'twofactor';
157        });
158
159        $classes = [];
160        foreach ($plugins as $plugin) {
161            $class = 'helper_plugin_' . $plugin;
162            if (is_a($class, Provider::class, true)) {
163                $classes[$plugin] = $class;
164            }
165        }
166
167        return $classes;
168    }
169
170}
171