22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['info'] = 'This factor forces users to read and accept a policy, otherwise they will be unable to authenticate to the system';
27 | $string['loginskip'] = 'Decline and log out';
28 | $string['loginsubmit'] = 'Accept';
29 | $string['pluginname'] = 'Login banner';
30 | $string['policytext'] = 'This is a placeholder policy text. This can be overridden in the sites language pack configuration menu.
';
31 | $string['privacy:metadata'] = 'The Policy factor plugin does not store any personal data';
32 | $string['summarycondition'] = 'accepts the user policy';
33 |
--------------------------------------------------------------------------------
/factor/loginbanner/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Loginbanner factor Settings.
19 | *
20 | * @package factor_loginbanner
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $enabled = new admin_setting_configcheckbox('factor_loginbanner/enabled',
29 | new lang_string('settings:enablefactor', 'tool_mfa'),
30 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
31 | $enabled->set_updatedcallback(function () {
32 | \tool_mfa\manager::do_factor_action('loginbanner', get_config('factor_loginbanner', 'enabled') ? 'enable' : 'disable');
33 | });
34 | $settings->add($enabled);
35 |
36 | $settings->add(new admin_setting_configtext('factor_loginbanner/weight',
37 | new lang_string('settings:weight', 'tool_mfa'),
38 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
39 |
--------------------------------------------------------------------------------
/factor/loginbanner/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_loginbanner
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2021030800; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->release = 2021030800; // Keep in lockstep with version.
31 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
32 | $plugin->component = 'factor_loginbanner';
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
--------------------------------------------------------------------------------
/factor/nosetup/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_nosetup\privacy;
18 |
19 | use core_privacy\local\metadata\null_provider;
20 | use core_privacy\local\legacy_polyfill;
21 |
22 | /**
23 | * Privacy provider.
24 | *
25 | * @package factor_nosetup
26 | * @author Peter Burnett
27 | * @copyright Catalyst IT
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class provider implements null_provider {
31 | use legacy_polyfill;
32 |
33 | /**
34 | * Get the language string identifier with the component's language
35 | * file to explain why this plugin stores no data.
36 | *
37 | * @return string
38 | */
39 | public static function _get_reason() {
40 | return 'privacy:metadata';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/factor/nosetup/db/tasks.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Task scheduler
19 | *
20 | * @package factor_nosetup
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $tasks = [
29 | [
30 | 'classname' => 'factor_nosetup\task\delete_unusable_factors',
31 | 'blocking' => 0,
32 | 'minute' => 'R',
33 | 'hour' => '0',
34 | 'day' => '*',
35 | 'month' => '*',
36 | 'dayofweek' => '*',
37 | ],
38 | ];
39 |
--------------------------------------------------------------------------------
/factor/nosetup/lang/en/factor_nosetup.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language strings.
19 | *
20 | * @package factor_nosetup
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['deleteunusablefactors'] = 'Delete unusable Nosetup factors';
27 | $string['info'] = 'This factor passes if the user has no other factors setup.';
28 | $string['pluginname'] = 'No other factors';
29 | $string['privacy:metadata'] = 'The No other factors plugin does not store any personal data';
30 | $string['summarycondition'] = 'has no other factors setup';
31 |
--------------------------------------------------------------------------------
/factor/nosetup/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_nosetup
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $enabled = new admin_setting_configcheckbox('factor_nosetup/enabled',
29 | new lang_string('settings:enablefactor', 'tool_mfa'),
30 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
31 | $enabled->set_updatedcallback(function () {
32 | \tool_mfa\manager::do_factor_action('nosetup', get_config('factor_nosetup', 'enabled') ? 'enable' : 'disable');
33 | });
34 | $settings->add($enabled);
35 |
36 | $settings->add(new admin_setting_configtext('factor_nosetup/weight',
37 | new lang_string('settings:weight', 'tool_mfa'),
38 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
39 |
--------------------------------------------------------------------------------
/factor/nosetup/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_nosetup
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2020042302; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'factor_nosetup';
32 | $plugin->release = 'v0.1';
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
--------------------------------------------------------------------------------
/factor/role/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_role\privacy;
18 |
19 | use core_privacy\local\metadata\null_provider;
20 | use core_privacy\local\legacy_polyfill;
21 |
22 | /**
23 | * Privacy provider.
24 | *
25 | * @package factor_role
26 | * @author Peter Burnett
27 | * @copyright Catalyst IT
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class provider implements null_provider {
31 | use legacy_polyfill;
32 |
33 | /**
34 | * Get the language string identifier with the component's language
35 | * file to explain why this plugin stores no data.
36 | *
37 | * @return string
38 | */
39 | public static function _get_reason() {
40 | return 'privacy:metadata';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/factor/role/lang/en/factor_role.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language strings.
19 | *
20 | * @package factor_role
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['pluginname'] = 'Role Factor';
27 | $string['privacy:metadata'] = 'The user capability factor plugin does not store any personal data';
28 | $string['settings:roles'] = 'Non-passing roles';
29 | $string['settings:roles_help'] = 'Select the roles that will not pass this factor. This allows you to force these roles to use other factors to authenticate.';
30 | $string['summarycondition'] = 'does NOT have any of the following roles assigned in any context: {$a}';
31 |
--------------------------------------------------------------------------------
/factor/role/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_role
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $enabled = new admin_setting_configcheckbox('factor_role/enabled',
29 | new lang_string('settings:enablefactor', 'tool_mfa'),
30 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
31 | $enabled->set_updatedcallback(function () {
32 | \tool_mfa\manager::do_factor_action('role', get_config('factor_role', 'enabled') ? 'enable' : 'disable');
33 | });
34 | $settings->add($enabled);
35 |
36 | $settings->add(new admin_setting_configtext('factor_role/weight',
37 | new lang_string('settings:weight', 'tool_mfa'),
38 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
39 |
40 | $choices = ['admin' => get_string('administrator')];
41 | $roles = get_all_roles();
42 | foreach ($roles as $role) {
43 | $choices[$role->id] = role_get_name($role);
44 | }
45 |
46 | $settings->add(new admin_setting_configmultiselect('factor_role/roles',
47 | new lang_string('settings:roles', 'factor_role'),
48 | new lang_string('settings:roles_help', 'factor_role'), ['admin'], $choices));
49 |
--------------------------------------------------------------------------------
/factor/role/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_role
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2020072100; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'factor_role';
32 | $plugin->release = 'v0.1';
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
--------------------------------------------------------------------------------
/factor/secq/classes/factor.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_secq;
18 |
19 | use tool_mfa\local\factor\object_factor_base;
20 |
21 | /**
22 | * Security Question factor class.
23 | *
24 | * @package factor_secq
25 | * @author Peter Burnett
26 | * @copyright Catalyst IT
27 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28 | */
29 | class factor extends object_factor_base {
30 |
31 | /**
32 | * Security Questions Factor implementation.
33 | *
34 | * @param array $data
35 | * @return stdClass the factor record, or null.
36 | */
37 | public function setup_user_factor($data) {
38 | // SETUP FUNCTIONALITY HERE.
39 | return true;
40 | }
41 |
42 | /**
43 | * Security Questions Factor implementation.
44 | *
45 | * @param stdClass $user the user to check against.
46 | * @return array
47 | */
48 | public function get_all_user_factors($user) {
49 | // FACTOR FUNCTIONALITY HERE.
50 | return [];
51 | }
52 |
53 | /**
54 | * Security Questions Factor implementation.
55 | *
56 | * {@inheritDoc}
57 | */
58 | public function has_input() {
59 | // CHANGE TO TRUE WHEN IMPLEMENTED.
60 | return false;
61 | }
62 |
63 | /**
64 | * Security Questions Factor implementation.
65 | * RETURN CORRECT STATE WHEN IMPLEMENTED.
66 | *
67 | * {@inheritDoc}
68 | */
69 | public function get_state() {
70 | return \tool_mfa\plugininfo\factor::STATE_NEUTRAL;
71 | }
72 |
73 | /**
74 | * Security Questions Factor implementation.
75 | *
76 | * @param mixed $state the state constant to set
77 | * @return bool
78 | */
79 | public function set_state($state) {
80 | // SET STATE CORRECTLY HERE.
81 | return true;
82 | }
83 |
84 | /**
85 | * Security Questions Factor Implementation.
86 | */
87 | public function get_no_redirect_urls() {
88 | return [new \moodle_url('/admin/tool/securityquestions/set_responses.php')];
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/factor/secq/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_secq\privacy;
18 |
19 | use core_privacy\local\metadata\null_provider;
20 | use core_privacy\local\legacy_polyfill;
21 |
22 | /**
23 | * Privacy provider.
24 | *
25 | * @package factor_secq
26 | * @author Peter Burnett
27 | * @copyright Catalyst IT
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class provider implements null_provider {
31 | use legacy_polyfill;
32 |
33 | /**
34 | * Get the language string identifier with the component's language
35 | * file to explain why this plugin stores no data.
36 | *
37 | * @return string
38 | */
39 | public static function _get_reason() {
40 | return 'privacy:metadata';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/factor/secq/lang/en/factor_secq.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language strings.
19 | *
20 | * @package factor_secq
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 | $string['info'] = 'Answer security questions as a factor.';
26 | $string['pluginname'] = 'Security questions';
27 | $string['privacy:metadata'] = 'The security questions factor plugin does not store any personal data';
28 | $string['summarycondition'] = 'answers security questions';
29 |
--------------------------------------------------------------------------------
/factor/secq/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_secq
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $enabled = new admin_setting_configcheckbox('factor_secq/enabled',
29 | new lang_string('settings:enablefactor', 'tool_mfa'),
30 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
31 | $enabled->set_updatedcallback(function () {
32 | \tool_mfa\manager::do_factor_action('secq', get_config('factor_secq', 'enabled') ? 'enable' : 'disable');
33 | });
34 | $settings->add($enabled);
35 |
36 | $settings->add(new admin_setting_configtext('factor_secq/weight',
37 | new lang_string('settings:weight', 'tool_mfa'),
38 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
39 |
--------------------------------------------------------------------------------
/factor/secq/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_secq
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2019102400; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'factor_secq';
32 | $plugin->release = 'v0.1';
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
--------------------------------------------------------------------------------
/factor/sms/classes/event/sms_sent.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_sms\event;
18 |
19 | /**
20 | * Event for a sent SMS
21 | *
22 | * @package factor_sms
23 | * @author Alex Morris
24 | * @copyright Catalyst IT
25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 | */
27 | class sms_sent extends \core\event\base {
28 |
29 | /**
30 | * Init sms sent event
31 | */
32 | protected function init() {
33 | $this->data['crud'] = 'r';
34 | $this->data['edulevel'] = self::LEVEL_OTHER;
35 | }
36 |
37 | /**
38 | * Returns non-localised event description with id's for admin use only.
39 | *
40 | * @return string
41 | */
42 | public function get_description() {
43 | return "The user with id '{$this->other['userid']}'" .
44 | " had a verification code sent to them via SMS
Information: {$this->other['debug']}";
45 | }
46 |
47 | /**
48 | * Returns localised general event name.
49 | *
50 | * Override in subclass, we can not make it static and abstract at the same time.
51 | *
52 | * @return string
53 | */
54 | public static function get_name() {
55 | return get_string('event:smssent', 'factor_sms');
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/factor/sms/classes/helper.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_sms;
18 |
19 | /**
20 | * Helper class for shared sms gateway functions
21 | *
22 | * @package factor_sms
23 | * @author Alex Morris
24 | * @copyright Catalyst IT
25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 | */
27 | class helper {
28 |
29 | /**
30 | * This function internationalises a number to E.164 standard.
31 | * https://46elks.com/kb/e164
32 | *
33 | * @param string $phonenumber the phone number to format.
34 | * @return string the formatted phone number.
35 | */
36 | public static function format_number(string $phonenumber): string {
37 | // Remove all whitespace, dashes and brackets.
38 | $phonenumber = preg_replace('/[ \(\)-]/', '', $phonenumber);
39 |
40 | // Number is already in international format. Do nothing.
41 | if (strpos($phonenumber, '+') === 0) {
42 | return $phonenumber;
43 | }
44 |
45 | // Strip leading 0 if found.
46 | if (strpos($phonenumber, '0') === 0) {
47 | $phonenumber = substr($phonenumber, 1);
48 | }
49 |
50 | // Prepend country code.
51 | $countrycode = get_config('factor_sms', 'countrycode');
52 | $phonenumber = '+' . $countrycode . $phonenumber;
53 |
54 | return $phonenumber;
55 | }
56 |
57 | /**
58 | * Redact the phone number for displaying on screen.
59 | *
60 | * @param string $phonenumber the phone number
61 | * @return string the redacted phone number
62 | */
63 | public static function redact_phonenumber(string $phonenumber): string {
64 | // Create partial num for display.
65 | $len = strlen($phonenumber);
66 | // Keep last 3 characters.
67 | $redacted = str_repeat('x', $len - 3);
68 | $redacted .= substr($phonenumber, -3);
69 | return $redacted;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/factor/sms/classes/local/smsgateway/gateway_interface.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * SMS Gateway interface
19 | *
20 | * @package factor_sms
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace factor_sms\local\smsgateway;
27 |
28 | interface gateway_interface {
29 |
30 | /**
31 | * Sends an SMS message
32 | *
33 | * @param string $messagecontent the content to send in the SMS message.
34 | * @param string $phonenumber the destination for the message.
35 | * @return bool true on message send success
36 | */
37 | public function send_sms_message(string $messagecontent, string $phonenumber): bool;
38 |
39 | /**
40 | * Add gateway specific settings to the SMS factor settings page.
41 | *
42 | * @param \admin_settingpage $settings
43 | * @return void
44 | */
45 | public static function add_settings($settings);
46 |
47 | /**
48 | * Returns whether or not the gateway is enabled
49 | *
50 | * @return bool
51 | */
52 | public static function is_gateway_enabled(): bool;
53 | }
54 |
--------------------------------------------------------------------------------
/factor/sms/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_sms\privacy;
18 |
19 | use core_privacy\local\metadata\null_provider;
20 | use core_privacy\local\legacy_polyfill;
21 |
22 | /**
23 | * Privacy provider.
24 | *
25 | * @package factor_sms
26 | * @author Peter Burnett
27 | * @copyright Catalyst IT
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class provider implements null_provider {
31 | use legacy_polyfill;
32 |
33 | /**
34 | * Get the language string identifier with the component's language
35 | * file to explain why this plugin stores no data.
36 | *
37 | * @return string
38 | */
39 | public static function _get_reason() {
40 | return 'privacy:metadata';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/factor/sms/db/upgrade.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * factor_sms upgrade.
19 | *
20 | * @package factor_sms
21 | * @copyright Alex Morris
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | /**
26 | * Factor sms upgrade helper function
27 | *
28 | * Sets the config of the gateway to aws_sns for factor sms
29 | *
30 | * @param int $oldversion
31 | */
32 | function xmldb_factor_sms_upgrade($oldversion) {
33 | if ($oldversion < 2021081300) {
34 | set_config('gateway', 'aws_sns', 'factor_sms');
35 | upgrade_plugin_savepoint(true, 2021081300, 'factor', 'sms');
36 | }
37 |
38 | return true;
39 | }
40 |
--------------------------------------------------------------------------------
/factor/sms/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_sms
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 | global $CFG, $OUTPUT;
28 |
29 | $enabled = new admin_setting_configcheckbox('factor_sms/enabled',
30 | new lang_string('settings:enablefactor', 'tool_mfa'),
31 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
32 | $enabled->set_updatedcallback(function () {
33 | \tool_mfa\manager::do_factor_action('sms', get_config('factor_sms', 'enabled') ? 'enable' : 'disable');
34 | });
35 | $settings->add($enabled);
36 |
37 | $settings->add(new admin_setting_configtext('factor_sms/weight',
38 | new lang_string('settings:weight', 'tool_mfa'),
39 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
40 |
41 | $settings->add(new admin_setting_configduration('factor_sms/duration',
42 | get_string('settings:duration', 'tool_mfa'),
43 | get_string('settings:duration_help', 'tool_mfa'), 30 * MINSECS, MINSECS));
44 |
45 | $codeslink = 'https://en.wikipedia.org/wiki/List_of_country_calling_codes';
46 | $link = \html_writer::link($codeslink, $codeslink);
47 |
48 | $settings->add(new admin_setting_configtext('factor_sms/countrycode',
49 | get_string('settings:countrycode', 'factor_sms'),
50 | get_string('settings:countrycode_help', 'factor_sms', $link), '', PARAM_INT));
51 |
52 | $gateways = [
53 | 'aws_sns' => get_string('settings:aws', 'factor_sms'),
54 | 'modica' => get_string('settings:modica', 'factor_sms'),
55 | ];
56 |
57 | $settings->add(new admin_setting_configselect('factor_sms/gateway',
58 | get_string('settings:gateway', 'factor_sms'),
59 | get_string('settings:gateway_help', 'factor_sms'),
60 | 'aws_sns', $gateways));
61 |
62 | if (empty(get_config('factor_sms', 'gateway'))) {
63 | return;
64 | }
65 |
66 | $class = '\factor_sms\local\smsgateway\\' . get_config('factor_sms', 'gateway');
67 | call_user_func($class . '::add_settings', $settings);
68 |
--------------------------------------------------------------------------------
/factor/sms/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_sms
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2021081300; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'factor_sms';
32 | $plugin->release = 'v0.1';
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
--------------------------------------------------------------------------------
/factor/token/classes/event/token_created.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_token\event;
18 | /**
19 | * Event for a token being created for a user.
20 | *
21 | * @package factor_token
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 | class token_created extends \core\event\base {
27 |
28 | /**
29 | * Create instance of event.
30 | *
31 | * @param stdClass $user the User object of the User who had the token creeated.
32 | * @param array $state an array of the state of the token.
33 | *
34 | * @return token_created the token_created_event event
35 | *
36 | * @throws \coding_exception
37 | */
38 | public static function token_created_event($user, $state) {
39 | $data = [
40 | 'relateduserid' => $user->id,
41 | 'context' => \context_user::instance($user->id),
42 | 'other' => [
43 | 'userid' => $user->id,
44 | 'state' => json_encode($state),
45 | ],
46 | ];
47 |
48 | return self::create($data);
49 | }
50 |
51 | /**
52 | * Init method.
53 | *
54 | * @return void
55 | */
56 | protected function init() {
57 | $this->data['crud'] = 'c';
58 | $this->data['edulevel'] = self::LEVEL_OTHER;
59 | }
60 |
61 | /**
62 | * Returns description of what happened.
63 | *
64 | * @return string
65 | */
66 | public function get_description() {
67 | $info = json_decode($this->other['state']);
68 | $string = '
';
69 | foreach ($info as $name => $value) {
70 | if ($name === 'expiry') {
71 | $value = userdate($value);
72 | }
73 |
74 | $string .= ucwords($name) . ': ' . $value . '
';
75 | }
76 |
77 | return "The user with id '{$this->other['userid']}' had an MFA token stored on their device.
Information:" . $string;
78 | }
79 |
80 | /**
81 | * Return localised event name.
82 | *
83 | * @return string
84 | * @throws \coding_exception
85 | */
86 | public static function get_name() {
87 | return get_string('event:token_created', 'factor_token');
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/factor/token/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_token\privacy;
18 |
19 | use core_privacy\local\metadata\null_provider;
20 | use core_privacy\local\legacy_polyfill;
21 |
22 | /**
23 | * Privacy provider.
24 | *
25 | * @package factor_token
26 | * @author Peter Burnett
27 | * @copyright Catalyst IT
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class provider implements null_provider {
31 | use legacy_polyfill;
32 |
33 | /**
34 | * Get the language string identifier with the component's language
35 | * file to explain why this plugin stores no data.
36 | *
37 | * @return string
38 | */
39 | public static function _get_reason() {
40 | return 'privacy:metadata';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/factor/token/lang/en/factor_token.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language strings.
19 | *
20 | * @package factor_token
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['event:token_created'] = 'MFA token created.';
27 | $string['form:trust'] = 'Trust this device for {$a}.';
28 | $string['pluginname'] = 'Trust this device';
29 | $string['privacy:metadata'] = 'The token factor plugin does not store any personal data.';
30 | $string['settings:expireovernight'] = 'Expire trust overnight';
31 | $string['settings:expireovernight_help'] = 'This forces tokens to expire overnight, preventing mid-day interruptions for users. Instead they will be asked to MFA authenticate at the start of a day after expiry.';
32 | $string['settings:expiry'] = 'Trust duration';
33 | $string['settings:expiry_help'] = 'The duration a device is trusted before requiring a new MFA authentication.';
34 | $string['settings:adminexpiry'] = 'Administrator trust duration';
35 | $string['settings:adminexpiry_help'] = 'The duration an administrator device is trusted before requiring a new MFA authentication. This allows tighter restrictions on site administrators, or no trust.';
36 | $string['summarycondition'] = 'the user has previously trusted this device';
37 |
--------------------------------------------------------------------------------
/factor/token/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_token
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $enabled = new admin_setting_configcheckbox('factor_token/enabled',
30 | new lang_string('settings:enablefactor', 'tool_mfa'),
31 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
32 | $enabled->set_updatedcallback(function () {
33 | \tool_mfa\manager::do_factor_action('token', get_config('factor_token', 'enabled') ? 'enable' : 'disable');
34 | });
35 | $settings->add($enabled);
36 |
37 | $settings->add(new admin_setting_configtext('factor_token/weight',
38 | new lang_string('settings:weight', 'tool_mfa'),
39 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
40 |
41 | $settings->add(new admin_setting_configduration('factor_token/expiry',
42 | new lang_string('settings:expiry', 'factor_token'),
43 | new lang_string('settings:expiry_help', 'factor_token'), DAYSECS));
44 |
45 | $settings->add(new admin_setting_configduration('factor_token/adminexpiry',
46 | new lang_string('settings:adminexpiry', 'factor_token'),
47 | new lang_string('settings:adminexpiry_help', 'factor_token'), DAYSECS));
48 |
49 | $settings->add(new admin_setting_configcheckbox('factor_token/expireovernight',
50 | new lang_string('settings:expireovernight', 'factor_token'),
51 | new lang_string('settings:expireovernight_help', 'factor_token'), 1));
52 |
--------------------------------------------------------------------------------
/factor/token/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_token
21 | * @subpackage tool_mfa
22 | * @author Peter Burnett
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2023080100; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'factor_token';
32 | $plugin->release = 2022011700;
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
36 | // Fix version numbers that are higher than 4.3 core.
37 | if (!during_initial_install() && (int) get_config('factor_token', 'version') >= 2023100900) {
38 | set_config('version', '2023080100', 'factor_token');
39 | }
40 |
--------------------------------------------------------------------------------
/factor/totp/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_totp\privacy;
18 |
19 | use core_privacy\local\metadata\null_provider;
20 | use core_privacy\local\legacy_polyfill;
21 |
22 | /**
23 | * Privacy provider.
24 | *
25 | * @package factor_totp
26 | * @author Mikhail Golenkov
27 | * @copyright Catalyst IT
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class provider implements null_provider {
31 | use legacy_polyfill;
32 |
33 | /**
34 | * Get the language string identifier with the component's language
35 | * file to explain why this plugin stores no data.
36 | *
37 | * @return string
38 | */
39 | public static function _get_reason() {
40 | return 'privacy:metadata';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/factor/totp/extlib/Assert/AssertionFailedException.php:
--------------------------------------------------------------------------------
1 | propertyPath = $propertyPath;
39 | $this->value = $value;
40 | $this->constraints = $constraints;
41 | }
42 |
43 | /**
44 | * User controlled way to define a sub-property causing
45 | * the failure of a currently asserted objects.
46 | *
47 | * Useful to transport information about the nature of the error
48 | * back to higher layers.
49 | *
50 | * @return string|null
51 | */
52 | public function getPropertyPath()
53 | {
54 | return $this->propertyPath;
55 | }
56 |
57 | /**
58 | * Get the value that caused the assertion to fail.
59 | *
60 | * @return mixed
61 | */
62 | public function getValue()
63 | {
64 | return $this->value;
65 | }
66 |
67 | /**
68 | * Get the constraints that applied to the failed assertion.
69 | *
70 | * @return array
71 | */
72 | public function getConstraints(): array
73 | {
74 | return $this->constraints;
75 | }
76 | }
--------------------------------------------------------------------------------
/factor/totp/extlib/OTPHP/TOTPInterface.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_totp
21 | * @subpackage tool_mfa
22 | * @author Mikhail Golenkov
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $enabled = new admin_setting_configcheckbox('factor_totp/enabled',
30 | new lang_string('settings:enablefactor', 'tool_mfa'),
31 | new lang_string('settings:enablefactor_help', 'tool_mfa'), 0);
32 | $enabled->set_updatedcallback(function () {
33 | \tool_mfa\manager::do_factor_action('totp', get_config('factor_totp', 'enabled') ? 'enable' : 'disable');
34 | });
35 | $settings->add($enabled);
36 |
37 | $settings->add(new admin_setting_configtext('factor_totp/weight',
38 | new lang_string('settings:weight', 'tool_mfa'),
39 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
40 |
41 | $settings->add(new admin_setting_configduration('factor_totp/window',
42 | new lang_string('settings:window', 'factor_totp'),
43 | new lang_string('settings:window_help', 'factor_totp'), 30));
44 |
45 | $settings->add(new admin_setting_configcheckbox('factor_totp/totplink',
46 | new lang_string('settings:totplink', 'factor_totp'),
47 | new lang_string('settings:totplink_help', 'factor_totp'), 1));
48 |
--------------------------------------------------------------------------------
/factor/totp/thirdpartylibs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | extlib/Assert
5 | Assert
6 |
7 | MIT
8 | 2.1+
9 |
10 |
11 | extlib/OTPHP
12 | OTPHP
13 |
14 | MIT
15 | 2.1+
16 |
17 |
18 | extlib/ParagonIE
19 | ParagonIE
20 |
21 | Custom
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/factor/totp/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_totp
21 | * @subpackage tool_mfa
22 | * @author Mikhail Golenkov
23 | * @copyright Catalyst IT
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | defined('MOODLE_INTERNAL') || die();
28 |
29 | $plugin->version = 2021021700; // The current plugin version (Date: YYYYMMDDXX).
30 | $plugin->release = 2021021700;
31 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
32 | $plugin->component = 'factor_totp';
33 | $plugin->maturity = MATURITY_STABLE;
34 | $plugin->dependencies = ['tool_mfa' => 2019102400];
35 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/.gitignore:
--------------------------------------------------------------------------------
1 | # Netbeans project
2 | nbproject/
3 | /index.php
4 |
5 |
6 | # .pem files from FIDO Alliance Metadata Service (MDS)
7 | _test/rootCertificates/mds/*.pem
8 | _test/rootCertificates/mds/lastMdsFetch.txt
9 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright © 2022 Lukas Buchs
4 | Copyright © 2018 Thomas Bleeker (CBOR & ByteBuffer part)
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/_test/rootCertificates/apple.pem:
--------------------------------------------------------------------------------
1 | Certificate:
2 | Data:
3 | Version: 3 (0x2)
4 | Serial Number:
5 | 68:1d:01:6c:7a:3c:e3:02:25:a5:01:94:28:47:57:71
6 |
7 | Signature Algorithm: ecdsa-with-SHA384
8 |
9 | Issuer:
10 | stateOrProvinceName = California
11 | organizationName = Apple Inc.
12 | commonName = Apple WebAuthn Root CA
13 |
14 | Validity
15 | Not Before: Mar 18 18:21:32 2020 GMT
16 | Not After : Mar 15 00:00:00 2045 GMT
17 |
18 | Subject:
19 | stateOrProvinceName = California
20 | organizationName = Apple Inc.
21 | commonName = Apple WebAuthn Root CA
22 |
23 | Subject Public Key Info:
24 | Public Key Algorithm: id-ecPublicKey
25 | ASN1 OID: secp384r1
26 |
27 | X509v3 extensions:
28 | X509v3 Basic Constraints: critical
29 | CA:TRUE
30 | X509v3 Subject Key Identifier:
31 | 26:D7:64:D9:C5:78:C2:5A:67:D1:A7:DE:6B:12:D0:1B:63:F1:C6:D7
32 | X509v3 Key Usage: critical
33 | Certificate Sign, CRL Sign
34 |
35 | -----BEGIN CERTIFICATE-----
36 | MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
37 | HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
38 | bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
39 | NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
40 | A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
41 | AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
42 | xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
43 | pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
44 | 2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
45 | MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
46 | jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
47 | 1bWeT0vT
48 | -----END CERTIFICATE-----
49 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/_test/rootCertificates/globalSign.pem:
--------------------------------------------------------------------------------
1 | Certificate:
2 | Data:
3 | Version: 3 (0x2)
4 | Serial Number:
5 | 04:00:00:00:00:01:0f:86:26:e6:0d
6 | Signature Algorithm: sha1WithRSAEncryption
7 | Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
8 | Validity
9 | Not Before: Dec 15 08:00:00 2006 GMT
10 | Not After : Dec 15 08:00:00 2021 GMT
11 | Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
12 | Subject Public Key Info:
13 | Public Key Algorithm: rsaEncryption
14 | Public-Key: (2048 bit)
15 |
16 | -----BEGIN CERTIFICATE-----
17 | MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
18 | A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
19 | Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
20 | MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
21 | A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
22 | hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
23 | v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
24 | eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
25 | tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
26 | C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
27 | zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
28 | mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
29 | V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
30 | bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
31 | 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
32 | J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
33 | 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
34 | ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
35 | AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
36 | TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
37 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/_test/rootCertificates/hypersecu.pem:
--------------------------------------------------------------------------------
1 | HyperFIDO U2F Security Key Attestation CA
2 | https://hypersecu.com/support/downloads/attestation
3 |
4 | Last Update: 2017-01-01
5 |
6 | HyperFIDO U2F Security Key devices which contain attestation certificates signed by a set of CAs.
7 | This file contains the CA certificates that Relying Parties (RP) need to configure their software
8 | with to be able to verify U2F device certificates.
9 |
10 | The file will be updated as needed when we publish more CA certificates.
11 |
12 | Issuer: CN=FT FIDO 0100
13 |
14 | -----BEGIN CERTIFICATE-----
15 | MIIBjTCCATOgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxGVCBGSURP
16 | IDAxMDAwHhcNMTQwNzAxMTUzNjI2WhcNNDQwNzAzMTUzNjI2WjAXMRUwEwYDVQQD
17 | EwxGVCBGSURPIDAxMDAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASxdLxJx8ol
18 | S3DS5cIHzunPF0gg69d+o8ZVCMJtpRtlfBzGuVL4YhaXk2SC2gptPTgmpZCV2vbN
19 | fAPi5gOF0vbZo3AwbjAdBgNVHQ4EFgQUXt4jWlYDgwhaPU+EqLmeM9LoPRMwPwYD
20 | VR0jBDgwNoAUXt4jWlYDgwhaPU+EqLmeM9LoPROhG6QZMBcxFTATBgNVBAMTDEZU
21 | IEZJRE8gMDEwMIIBATAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQC2
22 | D9o9cconKTo8+4GZPyZBJ3amc8F0/kzyidX9dhrAIAIgM9ocs5BW/JfmshVP9Mb+
23 | Joa/kgX4dWbZxrk0ioTfJZg=
24 | -----END CERTIFICATE-----
25 |
26 |
27 | Certificate:
28 | Data:
29 | Version: 3 (0x2)
30 | Serial Number: 4107 (0x100b)
31 | Signature Algorithm: ecdsa-with-SHA256
32 | Issuer:
33 | commonName = HYPERFIDO 0200
34 | organizationName = HYPERSECU
35 | countryName = CA
36 | Validity
37 | Not Before: Jan 1 00:00:00 2018 GMT
38 | Not After : Dec 31 23:59:59 2047 GMT
39 | Subject:
40 | commonName = HYPERFIDO 0200
41 | organizationName = HYPERSECU
42 | countryName = CA
43 |
44 |
45 | -----BEGIN CERTIFICATE-----
46 | MIIBxzCCAWygAwIBAgICEAswCgYIKoZIzj0EAwIwOjELMAkGA1UEBhMCQ0ExEjAQ
47 | BgNVBAoMCUhZUEVSU0VDVTEXMBUGA1UEAwwOSFlQRVJGSURPIDAyMDAwIBcNMTgw
48 | MTAxMDAwMDAwWhgPMjA0NzEyMzEyMzU5NTlaMDoxCzAJBgNVBAYTAkNBMRIwEAYD
49 | VQQKDAlIWVBFUlNFQ1UxFzAVBgNVBAMMDkhZUEVSRklETyAwMjAwMFkwEwYHKoZI
50 | zj0CAQYIKoZIzj0DAQcDQgAErKUI1G0S7a6IOLlmHipLlBuxTYjsEESQvzQh3dB7
51 | dvxxWWm7kWL91rq6S7ayZG0gZPR+zYqdFzwAYDcG4+aX66NgMF4wHQYDVR0OBBYE
52 | FLZYcfMMwkQAGbt3ryzZFPFypmsIMB8GA1UdIwQYMBaAFLZYcfMMwkQAGbt3ryzZ
53 | FPFypmsIMAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMC
54 | A0kAMEYCIQCG2/ppMGt7pkcRie5YIohS3uDPIrmiRcTjqDclKVWg0gIhANcPNDZH
55 | E2/zZ+uB5ThG9OZus+xSb4knkrbAyXKX2zm/
56 | -----END CERTIFICATE-----
57 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/_test/rootCertificates/mds/.gitkeep:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/_test/rootCertificates/solo.pem:
--------------------------------------------------------------------------------
1 | Solokeys FIDO2/U2F Device Attestation CA
2 | ========================================
3 | Data:
4 | Version: 1 (0x0)
5 | Serial Number: 14143382635911888524 (0xc44763928ff4be8c)
6 | Signature Algorithm: ecdsa-with-SHA256
7 |
8 | Issuer:
9 | emailAddress = hello@solokeys.com
10 | commonName = solokeys.com
11 | organizationalUnitName = Root CA
12 | organizationName = Solo Keys
13 | stateOrProvinceName = Maryland
14 | countryName = US
15 |
16 | Validity
17 | Not Before: Nov 11 12:51:42 2018 GMT
18 | Not After : Oct 29 12:51:42 2068 GMT
19 |
20 | Subject:
21 | emailAddress = hello@solokeys.com
22 | commonName = solokeys.com
23 | organizationalUnitName = Root CA
24 | organizationName = Solo Keys
25 | stateOrProvinceName = Maryland
26 | countryName = US
27 |
28 |
29 | -----BEGIN CERTIFICATE-----
30 | MIIB9DCCAZoCCQDER2OSj/S+jDAKBggqhkjOPQQDAjCBgDELMAkGA1UEBhMCVVMx
31 | ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQKDAlTb2xvIEtleXMxEDAOBgNVBAsM
32 | B1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlzLmNvbTEhMB8GCSqGSIb3DQEJARYS
33 | aGVsbG9Ac29sb2tleXMuY29tMCAXDTE4MTExMTEyNTE0MloYDzIwNjgxMDI5MTI1
34 | MTQyWjCBgDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQK
35 | DAlTb2xvIEtleXMxEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlz
36 | LmNvbTEhMB8GCSqGSIb3DQEJARYSaGVsbG9Ac29sb2tleXMuY29tMFkwEwYHKoZI
37 | zj0CAQYIKoZIzj0DAQcDQgAEWHAN0CCJVZdMs0oktZ5m93uxmB1iyq8ELRLtqVFL
38 | SOiHQEab56qRTB/QzrpGAY++Y2mw+vRuQMNhBiU0KzwjBjAKBggqhkjOPQQDAgNI
39 | ADBFAiEAz9SlrAXIlEu87vra54rICPs+4b0qhp3PdzcTg7rvnP0CIGjxzlteQQx+
40 | jQGd7rwSZuE5RWUPVygYhUstQO9zNUOs
41 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/_test/rootCertificates/yubico.pem:
--------------------------------------------------------------------------------
1 | Yubico U2F Device Attestation CA
2 | ================================
3 |
4 | Last Update: 2014-09-01
5 |
6 | Yubico manufacturer U2F devices that contains device attestation
7 | certificates signed by a set of Yubico CAs. This file contains the CA
8 | certificates that Relying Parties (RP) need to configure their
9 | software with to be able to verify U2F device certificates.
10 |
11 | This file has been signed with OpenPGP and you should verify the
12 | signature and the authenticity of the public key before trusting the
13 | content. The signature is located next to the file:
14 |
15 | https://developers.yubico.com/u2f/yubico-u2f-ca-certs.txt
16 | https://developers.yubico.com/u2f/yubico-u2f-ca-certs.txt.sig
17 |
18 | We will update this file from time to time when we publish more CA
19 | certificates.
20 |
21 | Name: Yubico U2F Root CA Serial 457200631
22 | Issued: 2014-08-01
23 |
24 | -----BEGIN CERTIFICATE-----
25 | MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ
26 | dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw
27 | MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290
28 | IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
29 | AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk
30 | 5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep
31 | 8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw
32 | nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT
33 | 9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw
34 | LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ
35 | hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN
36 | BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4
37 | MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt
38 | hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k
39 | LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U
40 | sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc
41 | U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==
42 | -----END CERTIFICATE-----
43 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lbuchs/webauthn",
3 | "description": "A simple PHP WebAuthn (FIDO2) server library",
4 | "keywords": [
5 | "webauthn", "authentication"
6 | ],
7 | "homepage": "https://github.com/lbuchs/webauthn",
8 | "license": "MIT",
9 | "authors": [
10 | {
11 | "name": "Lukas Buchs",
12 | "role": "Developer"
13 | }
14 | ],
15 | "require": {
16 | "php" : ">=8.0.0"
17 | },
18 | "autoload": {
19 | "psr-4": {
20 | "lbuchs\\WebAuthn\\": "src"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/factor/webauthn/.extlib/WebAuthn/src/Attestation/Format/None.php:
--------------------------------------------------------------------------------
1 |
8 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9 | */(utils);_exports.init=initialArgs=>{document.addEventListener("click",(async e=>{if(!e.target.closest("#id_submitbutton"))return;if(!navigator.credentials||!navigator.credentials.create)throw new Error("This browser does not support webauthn.");const getArgs=JSON.parse(initialArgs);if(!1===getArgs.success)throw new Error(getArgs.msg||"unknown error occured");e.preventDefault(),utils.recursiveBase64StrToArrayBuffer(getArgs);const authenticatorAttestationResponse=(cred=>{var _cred$response,_cred$response2,_cred$response3,_cred$response4;const response={id:null==cred?void 0:cred.rawId,clientDataJSON:null===(_cred$response=cred.response)||void 0===_cred$response?void 0:_cred$response.clientDataJSON,authenticatorData:null===(_cred$response2=cred.response)||void 0===_cred$response2?void 0:_cred$response2.authenticatorData,signature:null===(_cred$response3=cred.response)||void 0===_cred$response3?void 0:_cred$response3.signature,userHandle:null===(_cred$response4=cred.response)||void 0===_cred$response4?void 0:_cred$response4.userHandle};return Object.entries(response).forEach((_ref=>{let[key,value]=_ref;value&&(response[key]=utils.arrayBufferToBase64(value))})),response})(await navigator.credentials.get(getArgs));document.getElementById("id_response_input").value=JSON.stringify(authenticatorAttestationResponse),document.getElementById("id_response_input").form.submit()}))}}));
10 |
11 | //# sourceMappingURL=login.min.js.map
--------------------------------------------------------------------------------
/factor/webauthn/amd/build/register.min.js:
--------------------------------------------------------------------------------
1 | define("factor_webauthn/register",["exports","./utils"],(function(_exports,utils){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,utils=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}
2 | /**
3 | * For collecting WebAuthn authenticator details on factor setup
4 | *
5 | * @module factor_webauthn/register
6 | * @copyright Catalyst IT
7 | * @author Alex Morris
8 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9 | */(utils);_exports.init=initialCreateArgs=>{document.getElementById("id_submitbutton").disabled=!0,document.addEventListener("click",(async e=>{if(!e.target.closest("#factor_webauthn-register"))return;if(!navigator.credentials||!navigator.credentials.create)throw new Error("Browser not supported.");const createArgs=JSON.parse(initialCreateArgs);if(!1===createArgs.success)throw new Error(createArgs.msg||"unknown error occured");e.preventDefault(),utils.recursiveBase64StrToArrayBuffer(createArgs);const cred=await navigator.credentials.create(createArgs),authenticatorResponse={transports:cred.response.getTransports?cred.response.getTransports():null,clientDataJSON:cred.response.clientDataJSON?utils.arrayBufferToBase64(cred.response.clientDataJSON):null,attestationObject:cred.response.attestationObject?utils.arrayBufferToBase64(cred.response.attestationObject):null},inputResponse=document.getElementById("id_response_input");inputResponse.value=JSON.stringify(authenticatorResponse),document.getElementById("id_submitbutton").disabled=!1,inputResponse.form.elements.submitbutton.click()}))}}));
10 |
11 | //# sourceMappingURL=register.min.js.map
--------------------------------------------------------------------------------
/factor/webauthn/amd/build/utils.min.js:
--------------------------------------------------------------------------------
1 | define("factor_webauthn/utils",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.recursiveBase64StrToArrayBuffer=_exports.arrayBufferToBase64=void 0;
2 | /**
3 | * WebAuthn utility functions, for handling array buffers.
4 | *
5 | * @module factor_webauthn/utils
6 | * @copyright Catalyst IT
7 | * @author Alex Morris
8 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9 | */
10 | const recursiveBase64StrToArrayBuffer=obj=>{if("object"==typeof obj)for(let key in obj)if("string"==typeof obj[key]){let str=obj[key];if("=?BINARY?B?"===str.substring(0,"=?BINARY?B?".length)&&"?="===str.substring(str.length-"?=".length)){str=str.substring("=?BINARY?B?".length,str.length-"?=".length);const binaryString=window.atob(str),len=binaryString.length,bytes=new Uint8Array(len);for(let i=0;i{let binary="";const bytes=new Uint8Array(buffer),len=bytes.byteLength;for(let i=0;i.\n\n/**\n * WebAuthn utility functions, for handling array buffers.\n *\n * @module factor_webauthn/utils\n * @copyright Catalyst IT\n * @author Alex Morris \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst prefix = '=?BINARY?B?';\nconst suffix = '?=';\n\nexport const recursiveBase64StrToArrayBuffer = (obj) => {\n if (typeof obj !== 'object') {\n return;\n }\n for (let key in obj) {\n if (typeof obj[key] === 'string') {\n let str = obj[key];\n if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {\n str = str.substring(prefix.length, str.length - suffix.length);\n\n const binaryString = window.atob(str);\n const len = binaryString.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n obj[key] = bytes.buffer;\n }\n } else {\n recursiveBase64StrToArrayBuffer(obj[key]);\n }\n }\n};\n\nexport const arrayBufferToBase64 = (buffer) => {\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const len = bytes.byteLength;\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window.btoa(binary);\n};\n"],"names":["recursiveBase64StrToArrayBuffer","obj","key","str","substring","length","binaryString","window","atob","len","bytes","Uint8Array","i","charCodeAt","buffer","binary","byteLength","String","fromCharCode","btoa"],"mappings":";;;;;;;;;MA2BaA,gCAAmCC,SACzB,iBAARA,QAGN,IAAIC,OAAOD,OACY,iBAAbA,IAAIC,KAAmB,KAC1BC,IAAMF,IAAIC,QATX,gBAUCC,IAAIC,UAAU,EAVf,cAUyBC,SATzB,OAS+CF,IAAIC,UAAUD,IAAIE,OATjE,KASiFA,QAAoB,CACpGF,IAAMA,IAAIC,UAXX,cAW4BC,OAAQF,IAAIE,OAVxC,KAUwDA,cAEjDC,aAAeC,OAAOC,KAAKL,KAC3BM,IAAMH,aAAaD,OACnBK,MAAQ,IAAIC,WAAWF,SACxB,IAAIG,EAAI,EAAGA,EAAIH,IAAKG,IACrBF,MAAME,GAAKN,aAAaO,WAAWD,GAEvCX,IAAIC,KAAOQ,MAAMI,aAGrBd,gCAAgCC,IAAIC,6GAKZY,aAC5BC,OAAS,SACPL,MAAQ,IAAIC,WAAWG,QACvBL,IAAMC,MAAMM,eACb,IAAIJ,EAAI,EAAGA,EAAIH,IAAKG,IACrBG,QAAUE,OAAOC,aAAaR,MAAME,WAEjCL,OAAOY,KAAKJ"}
--------------------------------------------------------------------------------
/factor/webauthn/amd/src/login.js:
--------------------------------------------------------------------------------
1 | // This file is part of Moodle - http://moodle.org/
2 | //
3 | // Moodle is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // Moodle is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Moodle. If not, see .
15 |
16 | /**
17 | * For collecting WebAuthn authenticator details on login
18 | *
19 | * @module factor_webauthn/login
20 | * @copyright Catalyst IT
21 | * @author Alex Morris
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | import * as utils from './utils';
26 |
27 | const getAttestationResponse = (cred) => {
28 | const response = {
29 | id: cred?.rawId,
30 | clientDataJSON: cred.response?.clientDataJSON,
31 | authenticatorData: cred.response?.authenticatorData,
32 | signature: cred.response?.signature,
33 | userHandle: cred.response?.userHandle,
34 | };
35 |
36 | Object.entries(response).forEach(([key, value]) => {
37 | if (value) {
38 | response[key] = utils.arrayBufferToBase64(value);
39 | }
40 | });
41 |
42 | return response;
43 | };
44 |
45 | export const init = (initialArgs) => {
46 | document.addEventListener('click', async(e) => {
47 | if (!e.target.closest('#id_submitbutton')) {
48 | return;
49 | }
50 |
51 | if (!navigator.credentials || !navigator.credentials.create) {
52 | throw new Error('This browser does not support webauthn.');
53 | }
54 |
55 | const getArgs = JSON.parse(initialArgs);
56 | if (getArgs.success === false) {
57 | throw new Error(getArgs.msg || 'unknown error occured');
58 | }
59 |
60 | e.preventDefault();
61 |
62 | utils.recursiveBase64StrToArrayBuffer(getArgs);
63 |
64 | const cred = await navigator.credentials.get(getArgs);
65 | const authenticatorAttestationResponse = getAttestationResponse(cred);
66 |
67 | document.getElementById('id_response_input').value = JSON.stringify(authenticatorAttestationResponse);
68 | document.getElementById('id_response_input').form.submit();
69 | });
70 | };
71 |
--------------------------------------------------------------------------------
/factor/webauthn/amd/src/register.js:
--------------------------------------------------------------------------------
1 | // This file is part of Moodle - http://moodle.org/
2 | //
3 | // Moodle is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // Moodle is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Moodle. If not, see .
15 |
16 | /**
17 | * For collecting WebAuthn authenticator details on factor setup
18 | *
19 | * @module factor_webauthn/register
20 | * @copyright Catalyst IT
21 | * @author Alex Morris
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | import * as utils from './utils';
26 |
27 | export const init = (initialCreateArgs) => {
28 | document.getElementById('id_submitbutton').disabled = true;
29 | document.addEventListener('click', async(e) => {
30 | if (!e.target.closest('#factor_webauthn-register')) {
31 | return;
32 | }
33 |
34 | if (!navigator.credentials || !navigator.credentials.create) {
35 | throw new Error('Browser not supported.');
36 | }
37 |
38 | const createArgs = JSON.parse(initialCreateArgs);
39 | if (createArgs.success === false) {
40 | throw new Error(createArgs.msg || 'unknown error occured');
41 | }
42 | e.preventDefault();
43 |
44 | utils.recursiveBase64StrToArrayBuffer(createArgs);
45 |
46 | const cred = await navigator.credentials.create(createArgs);
47 |
48 | const authenticatorResponse = {
49 | transports: cred.response.getTransports ? cred.response.getTransports() : null,
50 | clientDataJSON: cred.response.clientDataJSON ? utils.arrayBufferToBase64(cred.response.clientDataJSON) : null,
51 | attestationObject: cred.response.attestationObject ? utils.arrayBufferToBase64(cred.response.attestationObject) : null,
52 | };
53 |
54 | const inputResponse = document.getElementById('id_response_input');
55 | inputResponse.value = JSON.stringify(authenticatorResponse);
56 | document.getElementById('id_submitbutton').disabled = false;
57 |
58 | // Do not use form.submit as it bypasses the change checker submit listener.
59 | inputResponse.form.elements.submitbutton.click();
60 | });
61 | };
62 |
--------------------------------------------------------------------------------
/factor/webauthn/amd/src/utils.js:
--------------------------------------------------------------------------------
1 | // This file is part of Moodle - http://moodle.org/
2 | //
3 | // Moodle is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // Moodle is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Moodle. If not, see .
15 |
16 | /**
17 | * WebAuthn utility functions, for handling array buffers.
18 | *
19 | * @module factor_webauthn/utils
20 | * @copyright Catalyst IT
21 | * @author Alex Morris
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | const prefix = '=?BINARY?B?';
26 | const suffix = '?=';
27 |
28 | export const recursiveBase64StrToArrayBuffer = (obj) => {
29 | if (typeof obj !== 'object') {
30 | return;
31 | }
32 | for (let key in obj) {
33 | if (typeof obj[key] === 'string') {
34 | let str = obj[key];
35 | if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
36 | str = str.substring(prefix.length, str.length - suffix.length);
37 |
38 | const binaryString = window.atob(str);
39 | const len = binaryString.length;
40 | const bytes = new Uint8Array(len);
41 | for (let i = 0; i < len; i++) {
42 | bytes[i] = binaryString.charCodeAt(i);
43 | }
44 | obj[key] = bytes.buffer;
45 | }
46 | } else {
47 | recursiveBase64StrToArrayBuffer(obj[key]);
48 | }
49 | }
50 | };
51 |
52 | export const arrayBufferToBase64 = (buffer) => {
53 | let binary = '';
54 | const bytes = new Uint8Array(buffer);
55 | const len = bytes.byteLength;
56 | for (let i = 0; i < len; i++) {
57 | binary += String.fromCharCode(bytes[i]);
58 | }
59 | return window.btoa(binary);
60 | };
61 |
--------------------------------------------------------------------------------
/factor/webauthn/classes/privacy/provider.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace factor_webauthn\privacy;
18 |
19 | /**
20 | * Privacy provider.
21 | *
22 | * @package factor_webauthn
23 | * @author Alex Morris
24 | * @copyright Catalyst IT
25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 | */
27 | class provider implements \core_privacy\local\metadata\null_provider {
28 |
29 | /**
30 | * Get the language string identifier with the component's language
31 | * file to explain why this plugin stores no data.
32 | *
33 | * @return string
34 | */
35 | public static function get_reason() : string {
36 | return 'privacy:metadata';
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/factor/webauthn/lang/en/factor_webauthn.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language strings.
19 | *
20 | * @package factor_webauthn
21 | * @author Alex Morris
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | $string['action:revoke'] = 'Revoke security key';
27 | $string['authenticator:ble'] = 'BLE';
28 | $string['authenticator:hybrid'] = 'Hybrid';
29 | $string['authenticator:internal'] = 'Internal';
30 | $string['authenticator:nfc'] = 'NFC';
31 | $string['authenticator:usb'] = 'USB';
32 | $string['authenticatorname'] = 'Security key name';
33 | $string['authenticatortypelimitation'] = 'Please note that you can only use security keys of one of these types: {$a}.
Registering other security keys is possible, but you cannot use them during login.';
34 | $string['error'] = 'Failed to authenticate';
35 | $string['info'] = 'Use a security key
';
36 | $string['loginexplanation'] = 'Your account settings require that you authenticate with your security key in addition to your password.';
37 | $string['loginskip'] = 'I don\'t have my security key';
38 | $string['loginsubmit'] = 'Verify security key';
39 | $string['pluginname'] = 'Security Key';
40 | $string['privacy:metadata'] = 'The WebAuthn factor plugin does not store any personal data';
41 | $string['register'] = 'Register security key';
42 | $string['settings:authenticatortypes'] = 'Types of security keys';
43 | $string['settings:authenticatortypes_help'] = 'Toggle certain types of security keys';
44 | $string['settings:userverification'] = 'User verification';
45 | $string['settings:userverification_help'] = 'Serves to ensure the person authenticating is in fact who they say they are. User verification can take various forms, such as password, PIN, fingerprint, etc.';
46 | $string['setupfactor'] = 'Setup security key';
47 | $string['summarycondition'] = 'using a security key';
48 | $string['userverification:discouraged'] = 'User verification should not be employed, for example to minimize user interaction';
49 | $string['userverification:preferred'] = 'User verification is preferred, authentication will not fail if user verification is missing';
50 | $string['userverification:required'] = 'User verification is required (e.g. by pin). Authentication fails if key does not have user verification';
51 | $string['userverificationrequired'] = 'Your security key must support user verification (e.g. pin input) to be eligible for registration.';
52 |
--------------------------------------------------------------------------------
/factor/webauthn/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Settings
19 | *
20 | * @package factor_webauthn
21 | * @author Alex Morris set_updatedcallback(function() {
32 | \tool_mfa\manager::do_factor_action('webauthn', get_config('factor_webauthn', 'enabled') ? 'enable' : 'disable');
33 | });
34 | $settings->add($enabled);
35 |
36 | $settings->add(new admin_setting_configtext('factor_webauthn/weight',
37 | new lang_string('settings:weight', 'tool_mfa'),
38 | new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT));
39 |
40 | $authenticators = [
41 | 'usb' => get_string('authenticator:usb', 'factor_webauthn'),
42 | 'nfc' => get_string('authenticator:nfc', 'factor_webauthn'),
43 | 'ble' => get_string('authenticator:ble', 'factor_webauthn'),
44 | 'hybrid' => get_string('authenticator:hybrid', 'factor_webauthn'),
45 | 'internal' => get_string('authenticator:internal', 'factor_webauthn'),
46 | ];
47 | $settings->add(new admin_setting_configmultiselect('factor_webauthn/authenticatortypes',
48 | new lang_string('settings:authenticatortypes', 'factor_webauthn'),
49 | new lang_string('settings:authenticatortypes_help', 'factor_webauthn'),
50 | array_keys($authenticators), $authenticators));
51 |
52 | $settings->add(new admin_setting_configselect('factor_webauthn/userverification',
53 | new lang_string('settings:userverification', 'factor_webauthn'),
54 | new lang_string('settings:userverification_help', 'factor_webauthn'),
55 | 'preferred',
56 | $userverification = [
57 | 'required' => get_string('userverification:required', 'factor_webauthn'),
58 | 'preferred' => get_string('userverification:preferred', 'factor_webauthn'),
59 | 'discouraged' => get_string('userverification:discouraged', 'factor_webauthn'),
60 | ]));
61 |
--------------------------------------------------------------------------------
/factor/webauthn/thirdpartylibs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | .extlib/WebAuthn
5 | WebAuthn
6 | 2.0.1
7 | MIT
8 | https://github.com/lbuchs/WebAuthn
9 |
10 |
11 |
--------------------------------------------------------------------------------
/factor/webauthn/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package factor_webauthn
21 | * @author Alex Morris version = 2023052400; // The current plugin version (Date: YYYYMMDDXX).
29 | $plugin->release = 2023052400;
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'factor_webauthn';
32 | $plugin->maturity = MATURITY_ALPHA;
33 | $plugin->dependencies = ['tool_mfa' => 2023031600];
34 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 | tests
21 |
22 |
23 | ../../../privacy/tests
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | input.tool-mfa-verification-code,
2 | .tool-mfa-verification-code input {
3 | /* Some elements must be important to override form element*/
4 | font-size: 1.25em !important;
5 | letter-spacing: 1.05em;
6 | font-family: monospace;
7 | width: 11.5em !important;
8 | }
--------------------------------------------------------------------------------
/templates/guide_link.mustache:
--------------------------------------------------------------------------------
1 | {{!
2 | This file is part of Moodle - http://moodle.org/
3 |
4 | Moodle is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | Moodle is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with Moodle. If not, see .
16 | }}
17 | {{!
18 | @template tool_mfa/guide_link
19 |
20 | Template for the link to the user guide.
21 |
22 | Example context (json):
23 | {
24 | }
25 | }}
26 |
--------------------------------------------------------------------------------
/tests/plugininfo_factor_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Tests for plugininfo.
19 | *
20 | * @package tool_mfa
21 | * @author Peter Burnett
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 | class plugininfo_factor_test extends advanced_testcase {
26 |
27 | public function test_get_next_user_factor() {
28 |
29 | $this->resetAfterTest(true);
30 |
31 | // Create and login a user.
32 | $user = $this->getDataGenerator()->create_user();
33 | $this->setUser($user);
34 |
35 | // Test that with no enabled factors, fallback is returned.
36 | $this->assertEquals(\tool_mfa\plugininfo\factor::get_next_user_factor()->name, 'fallback');
37 |
38 | // Setup enabled totp factor for user.
39 | set_config('enabled', 1, 'factor_totp');
40 | $totpfactor = \tool_mfa\plugininfo\factor::get_factor('totp');
41 | $totpdata = [
42 | 'secret' => 'fakekey',
43 | 'devicename' => 'fakedevice',
44 | ];
45 | $this->assertNotEmpty($totpfactor->setup_user_factor((object) $totpdata));
46 |
47 | // Test that factor now appears (from STATE_UNKNOWN).
48 | $this->assertEquals(\tool_mfa\plugininfo\factor::get_next_user_factor()->name, 'totp');
49 |
50 | // Now pass this factor, check for fallback.
51 | $totpfactor->set_state(\tool_mfa\plugininfo\factor::STATE_PASS);
52 | $this->assertEquals(\tool_mfa\plugininfo\factor::get_next_user_factor()->name, 'fallback');
53 |
54 | // Add in a no-input factor.
55 | set_config('enabled', 1, 'factor_auth');
56 | $this->assertEquals(2, count(\tool_mfa\plugininfo\factor::get_enabled_factors()));
57 |
58 | $authfactor = \tool_mfa\plugininfo\factor::get_factor('auth');
59 | $this->assertTrue($authfactor->is_enabled());
60 | $this->assertFalse($authfactor->has_setup());
61 |
62 | // Check that the next factor is still the fallback factor.
63 | $this->assertEquals(2, count(\tool_mfa\plugininfo\factor::get_active_user_factor_types()));
64 | $this->assertEquals(\tool_mfa\plugininfo\factor::get_next_user_factor()->name, 'fallback');
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/tool_mfa_testcase.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace tool_mfa\tests;
18 |
19 | defined('MOODLE_INTERNAL') || die();
20 |
21 | global $CFG;
22 | require_once($CFG->libdir.'/adminlib.php');
23 | require_once(__DIR__ . '/../lib.php');
24 |
25 | /**
26 | * Base testcase class for testing this plugin
27 | *
28 | * @package tool_mfa
29 | * @author Mikhail Golenkov
30 | * @author Peter Burnett
31 | * @copyright Catalyst IT
32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 | */
34 | abstract class tool_mfa_testcase extends \advanced_testcase {
35 |
36 | /**
37 | * Sets the state of the factor, in particular the weight and whether it is enabled
38 | *
39 | * @param string $factorname
40 | * @param int $enabled
41 | * @param int $weight
42 | */
43 | protected function set_factor_state($factorname, $enabled = 0, $weight = 100) {
44 | $factor = \tool_mfa\plugininfo\factor::get_factor($factorname);
45 | $this->set_factor_config($factor, 'enabled', $enabled);
46 | $this->set_factor_config($factor, 'weight', $weight);
47 | }
48 |
49 | /**
50 | * Sets config variable for given factor.
51 | *
52 | * @param object $factor object of the factor class
53 | * @param string $key
54 | * @param mixed $value
55 | */
56 | protected function set_factor_config($factor, $key, $value) {
57 | \tool_mfa\manager::set_factor_config([$key => $value], 'factor_' . $factor->name);
58 |
59 | if ($key == 'enabled') {
60 | if ($value == 1) {
61 | \tool_mfa\manager::do_factor_action($factor->name, 'enable');
62 | } else {
63 | \tool_mfa\manager::do_factor_action($factor->name, 'disable');
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/thirdpartylibs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | factor/totp/extlib/Assert
5 | Assert
6 |
7 | MIT
8 | 2.1+
9 |
10 |
11 | factor/totp/extlib/OTPHP
12 | OTPHP
13 |
14 | MIT
15 | 2.1+
16 |
17 |
18 | factor/totp/extlib/ParagonIE
19 | ParagonIE
20 |
21 | Custom
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/user_preferences.php:
--------------------------------------------------------------------------------
1 | .
16 | /**
17 | * User preferences page
18 | *
19 | * @package tool_mfa
20 | * @author Mikhail Golenkov
21 | * @copyright Catalyst IT
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | require_once(__DIR__ . '/../../../config.php');
26 |
27 | require_login(null, false);
28 | if (isguestuser()) {
29 | throw new require_login_exception('Guests are not allowed here.');
30 | }
31 |
32 | $action = optional_param('action', '', PARAM_TEXT);
33 | $factorid = optional_param('factorid', 0, PARAM_INT);
34 |
35 | $context = context_user::instance($USER->id);
36 | $PAGE->set_context($context);
37 | $PAGE->set_url('/admin/tool/mfa/user_preferences.php');
38 | $PAGE->set_pagelayout('standard');
39 | $PAGE->set_title(get_string('preferences:header', 'tool_mfa'));
40 | $PAGE->set_cacheable(false);
41 |
42 | if ($node = $PAGE->settingsnav->find('usercurrentsettings', null)) {
43 | $PAGE->navbar->add($node->get_content(), $node->action());
44 | }
45 | $PAGE->navbar->add(get_string('preferences:header', 'tool_mfa'), new \moodle_url('/admin/tool/mfa/user_preferences.php'));
46 | $OUTPUT = $PAGE->get_renderer('tool_mfa');
47 |
48 | echo $OUTPUT->header();
49 | if (!empty($action)) {
50 | if ($factorid != 0) {
51 | $instance = \tool_mfa\plugininfo\factor::get_instance_from_id($factorid);
52 | // Confirm factor is valid for the accessing user.
53 | if ($USER->id == $instance->userid) {
54 | $factor = \tool_mfa\plugininfo\factor::get_factor($instance->factor);
55 | $string = $factor->get_display_name().' - '.$instance->label;
56 | echo $OUTPUT->notification(get_string('factor'.$action, 'tool_mfa', $string), 'notifysuccess');
57 | }
58 | }
59 | }
60 |
61 | echo $OUTPUT->active_factors();
62 | echo $OUTPUT->available_factors();
63 |
64 | echo $OUTPUT->guide_link();
65 |
66 | \tool_mfa\manager::display_debug_notification();
67 |
68 | echo $OUTPUT->footer();
69 |
70 | if (!empty($SESSION->tool_mfa_setwantsurl) && $SESSION->tool_mfa_setwantsurl
71 | && \tool_mfa\manager::get_total_weight() >= 100) {
72 | unset($SESSION->wantsurl);
73 | }
74 |
--------------------------------------------------------------------------------
/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Plugin version and other meta-data are defined here.
19 | *
20 | * @package tool_mfa
21 | * @author Mikhail Golenkov
22 | * @copyright Catalyst IT
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $plugin->version = 2023080100; // The current plugin version (Date: YYYYMMDDXX).
29 | $plugin->release = 2023080100; // Same as version.
30 | $plugin->requires = 2022041908; // Support Moodle 4.0 and higher.
31 | $plugin->component = 'tool_mfa';
32 | $plugin->maturity = MATURITY_STABLE;
33 | $plugin->supported = [400, 402];
34 |
--------------------------------------------------------------------------------