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