From 5c28fc5d4e0875cbdfc8f149f9388b828cdbba83 Mon Sep 17 00:00:00 2001 From: Laur0r Date: Mon, 24 Aug 2020 14:59:38 +0200 Subject: [PATCH 1/9] telegram subplugin first draft --- factor/telegram/Telegram.php | 10 + .../classes/event/unauth_telegram.php | 100 +++++++ factor/telegram/classes/factor.php | 272 ++++++++++++++++++ factor/telegram/classes/form/telegram.php | 43 +++ factor/telegram/lang/en/factor_telegram.php | 57 ++++ factor/telegram/settings.php | 43 +++ factor/telegram/telegram.php | 99 +++++++ factor/telegram/version.php | 33 +++ 8 files changed, 657 insertions(+) create mode 100644 factor/telegram/Telegram.php create mode 100644 factor/telegram/classes/event/unauth_telegram.php create mode 100644 factor/telegram/classes/factor.php create mode 100644 factor/telegram/classes/form/telegram.php create mode 100644 factor/telegram/lang/en/factor_telegram.php create mode 100644 factor/telegram/settings.php create mode 100644 factor/telegram/telegram.php create mode 100644 factor/telegram/version.php diff --git a/factor/telegram/Telegram.php b/factor/telegram/Telegram.php new file mode 100644 index 00000000..1b2f5a8a --- /dev/null +++ b/factor/telegram/Telegram.php @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/factor/telegram/classes/event/unauth_telegram.php b/factor/telegram/classes/event/unauth_telegram.php new file mode 100644 index 00000000..7b69796e --- /dev/null +++ b/factor/telegram/classes/event/unauth_telegram.php @@ -0,0 +1,100 @@ +. + +/** + * Event for unauthorised email being received from MFA. + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +namespace factor_telegram\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event for when a user receives an unauthorised email from MFA. + * + * @property-read array $other { + * Extra information about event. + * } + * + * @package factor_email + * @author Peter Burnett + * @copyright Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +class unauth_telegram extends \core\event\base { + /** + * Create instance of event. + * + * @param stdClass $user the User object of the User who passed all MFA factor checks. + * @param string $ip the ip address the unauthorised email came from. + * @param string $useragent the browser fingerpring the unauthorised email came from. + * + * @return user_passed_mfa the user_passed_mfa event + * + * @throws \coding_exception + */ + public static function unauth_telegram_event($user, $ip, $useragent) { + + $data = array( + 'relateduserid' => null, + 'context' => \context_user::instance($user->id), + 'other' => array ( + 'userid' => $user->id, + 'ip' => $ip, + 'useragent' => $useragent + ) + ); + + return self::create($data); + } + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '{$this->other['userid']}' made an unauthorised login attempt using telegram verification from + IP '{$this->other['ip']}' with browser agent '{$this->other['useragent']}'."; + } + + /** + * Return localised event name. + * + * @return string + * @throws \coding_exception + */ + public static function get_name() { + return get_string('event:unauthtelegram', 'factor_telegram'); + } +} diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php new file mode 100644 index 00000000..d95bf496 --- /dev/null +++ b/factor/telegram/classes/factor.php @@ -0,0 +1,272 @@ +. + +/** + * Email factor class. + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace factor_telegram; + +defined('MOODLE_INTERNAL') || die(); + +use tool_mfa\local\factor\object_factor_base; + +class factor extends object_factor_base { + /** + * Telegram Factor implementation. + * + * {@inheritDoc} + */ + public function login_form_definition($mform) { + + $mform->addElement('text', 'verificationcode', get_string('verificationcode', 'factor_telegram')); + $mform->setType("verificationcode", PARAM_ALPHANUM); + return $mform; + } + + /** + * E-Mail Factor implementation. + * + * {@inheritDoc} + */ + public function login_form_definition_after_data($mform) { + $this->generate_and_telegram_code(); + return $mform; + } + + /** + * E-Mail Factor implementation. + * + * {@inheritDoc} + */ + public function login_form_validation($data) { + global $USER; + $return = array(); + + if (!$this->check_verification_code($data['verificationcode'])) { + $return['verificationcode'] = get_string('error:wrongverification', 'factor_telegram'); + } + + return $return; + } + + /** + * Telegram Factor implementation. + * + * {@inheritDoc} + */ + public function get_all_user_factors($user) { + global $DB; + + $records = $DB->get_records('tool_mfa', array( + 'userid' => $user->id, + 'factor' => $this->name, + 'label' => $user->telegram + )); + + if (!empty($records)) { + return $records; + } + + // Null records returned, build new record. + $record = array( + 'userid' => $user->id, + 'factor' => $this->name, + 'label' => $user->telegram, + 'createdfromip' => $user->lastip, + 'timecreated' => time(), + 'revoked' => 0, + ); + $record['id'] = $DB->insert_record('tool_mfa', $record, true); + return [(object) $record]; + } + + /** + * E-Mail Factor implementation. + * + * {@inheritDoc} + */ + public function has_input() { + if (self::is_ready()) { + return true; + } + return false; + } + + /** + * E-Mail Factor implementation. + * + * {@inheritDoc} + */ + public function get_state() { + if (!self::is_ready()) { + return \tool_mfa\plugininfo\factor::STATE_NEUTRAL; + } + + return parent::get_state(); + } + + /** + * Checks whether user telegram is correctly configured. + * + * @return bool + */ + private static function is_ready() { + global $DB, $USER; + + if (empty($USER->email)) { //TODO + return false; + } + if (!validate_email($USER->email)) { //TODO + return false; + } + if (over_bounce_threshold($USER)) { + return false; + } + + // If this factor is revoked, set to not ready. + if ($DB->record_exists('tool_mfa', array('userid' => $USER->id, 'factor' => 'telegram', 'revoked' => 1))) { + return false; + } + return true; + } + + /** + * Generates and emails the code for login to the user, stores codes in DB. + * + * @return void + */ + private function generate_and_telegram_code() { + global $DB, $USER; + + // Get instance that isnt parent email type (label check). + // This check must exclude the main singleton record, with the label as the email. + // It must only grab the record with the user agent as the label. + $sql = 'SELECT * + FROM {tool_mfa} + WHERE userid = ? + AND factor = ? + AND NOT label = ?'; + + $record = $DB->get_record_sql($sql, array($USER->id, 'telegram', $USER->email)); //TODO + $duration = get_config('factor_telegram', 'duration'); + $newcode = random_int(100000, 999999); + + if (empty($record)) { + // No code active, generate new code. + $instanceid = $DB->insert_record('tool_mfa', array( + 'userid' => $USER->id, + 'factor' => 'telegram', + 'secret' => $newcode, + 'label' => $_SERVER['HTTP_USER_AGENT'], + 'timecreated' => time(), + 'createdfromip' => $USER->lastip, + 'timemodified' => time(), + 'lastverified' => time(), + 'revoked' => 0, + ), true); + + } else if ($record->timecreated + $duration < time()) { + // Old code found. Keep id, update fields. + $DB->update_record('tool_mfa', array( + 'id' => $record->id, + 'secret' => $newcode, + 'label' => $_SERVER['HTTP_USER_AGENT'], + 'timecreated' => time(), + 'createdfromip' => $USER->lastip, + 'timemodified' => time(), + 'lastverified' => time(), + 'revoked' => 0, + )); + $instanceid = $record->id; + } + } + + /** + * Verifies entered code against stored DB record. + * + * @return bool + */ + private function check_verification_code($enteredcode) { + global $DB, $USER; + $duration = get_config('factor_telegram', 'duration'); + + // Get instance that isnt parent email type (label check). + // This check must exclude the main singleton record, with the label as the email. + // It must only grab the record with the user agent as the label. + $sql = 'SELECT * + FROM {tool_mfa} + WHERE userid = ? + AND factor = ? + AND NOT label = ?'; + $record = $DB->get_record_sql($sql, array($USER->id, 'telegram', $USER->email)); //TODO + + if ($enteredcode == $record->secret) { + if ($record->timecreated + $duration > time()) { + return true; + } + } + return false; + } + + /** + * Cleans up email records once MFA passed. + * + * {@inheritDoc} + */ + public function post_pass_state() { + global $DB, $USER; + // Delete all email records except base record. + $selectsql = 'userid = ? + AND factor = ? + AND NOT label = ?'; + $DB->delete_records_select('tool_mfa', $selectsql, array($USER->id, 'telegram', $USER->email)); //TODO + + // Update factor timeverified. + parent::post_pass_state(); + } + + /** + * Email factor implementation. + * Email page must be safe to authorise session from link. + * + * {@inheritDoc} + */ + public function get_no_redirect_urls() { + $telegram = new \moodle_url('/admin/tool/mfa/factor/telegram/telegram.php'); + return array($telegram); + } + + /** + * Email factor implementation. + * + * {@inheritDoc} + */ + public function possible_states($user) { + // Email can return all states. + return array( + \tool_mfa\plugininfo\factor::STATE_FAIL, + \tool_mfa\plugininfo\factor::STATE_PASS, + \tool_mfa\plugininfo\factor::STATE_NEUTRAL, + \tool_mfa\plugininfo\factor::STATE_UNKNOWN, + ); + } +} diff --git a/factor/telegram/classes/form/telegram.php b/factor/telegram/classes/form/telegram.php new file mode 100644 index 00000000..1c82d632 --- /dev/null +++ b/factor/telegram/classes/form/telegram.php @@ -0,0 +1,43 @@ +. +/** + * Revoke email form. + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace factor_telegram\form; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir . "/formslib.php"); + +class telegram extends \moodleform { + + public function definition() { + $mform = $this->_form; + $mform->addElement('html', get_string('telegram:accident', 'factor_telegram')); + $this->add_action_buttons(true, get_string('continue')); + } + + public function validation($data, $files) { + $errors = parent::validation($data, $files); + return $errors; + } +} diff --git a/factor/telegram/lang/en/factor_telegram.php b/factor/telegram/lang/en/factor_telegram.php new file mode 100644 index 00000000..0743a21c --- /dev/null +++ b/factor/telegram/lang/en/factor_telegram.php @@ -0,0 +1,57 @@ +. + +/** + * Language strings. + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['telegram:subject'] = 'Your confirmation code'; +$string['telegram:message'] = 'You are trying to log in to Moodle. Your confirmation code is \'{$a->secret}\'. + Alternatively you can click {$a->link} from the same device to authorise this session.'; +$string['telegram:ipinfo'] = 'IP Information'; +$string['telegram:originatingip'] = 'This login request was made from \'{$a}\''; +$string['telegram:uadescription'] = 'Browser identity for this request:'; +$string['telegram:browseragent'] = 'The browser details for this request are: \'{$a}\''; +$string['telegram:revokelink'] = 'If this wasn\'t you, follow {$a} to stop this login attempt.'; +$string['telegram:geoinfo'] = 'This request appears to have originated from approximately {$a->city}, {$a->country}.'; +$string['telegram:link'] = 'this link'; +$string['telegram:revokesuccess'] = 'This code has been successfully revoked. All sessions for {$a} have been ended. + telegram will not be usable as a factor until account security has been verified.'; +$string['telegram:accident'] = 'If you did not request this telegram, click continue to attempt to invalidate the login attempt. + If you clicked this link by accident, click cancel, and no action will be taken.'; +$string['settings:duration'] = 'Validity duration'; +$string['settings:duration_help'] = 'The period of time that the code is valid.'; +$string['settings:suspend'] = 'Suspend unauthorised accounts'; +$string['settings:suspend_help'] = 'Check this to suspend user accounts if an unauthorised telegram verification is received.'; +$string['event:unauthtelegram'] = 'Unauthorised telegram received'; +$string['unauthtelegram'] = 'Unauthorised telegram'; +$string['error:wrongverification'] = 'Incorrect verification code'; +$string['error:badcode'] = 'Code was not found. This may be an old link, a new code may have been telegramed, or the login attempt with this code was successful.'; +$string['error:parameters'] = 'Incorrect page parameters.'; +$string['loginsubmit'] = 'Verify Code'; +$string['loginskip'] = "I didn't receive a code"; +$string['info'] = '

Built-in factor. Uses e-mail address mentioned in user profile for sending verification codes

'; +$string['pluginname'] = 'E-Mail Factor'; +$string['privacy:metadata'] = 'The E-Mail Factor plugin does not store any personal data'; +$string['setupfactor'] = 'E-Mail Factor setup'; +$string['verificationcode'] = 'Enter verification code for confirmation'; +$string['verificationcode_help'] = 'Verification code has been sent to your telegram address'; +$string['summarycondition'] = 'has valid telegram setup'; diff --git a/factor/telegram/settings.php b/factor/telegram/settings.php new file mode 100644 index 00000000..9e5c6874 --- /dev/null +++ b/factor/telegram/settings.php @@ -0,0 +1,43 @@ +. + +/** + * Settings + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +defined('MOODLE_INTERNAL') || die(); + +$settings->add(new admin_setting_configcheckbox('factor_telegram/enabled', + new lang_string('settings:enablefactor', 'tool_mfa'), + new lang_string('settings:enablefactor_help', 'tool_mfa'), 0)); + +$settings->add(new admin_setting_configtext('factor_telegram/weight', + new lang_string('settings:weight', 'tool_mfa'), + new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT)); + +$settings->add(new admin_setting_configduration('factor_telegram/duration', + get_string('settings:duration', 'factor_telegram'), + get_string('settings:duration_help', 'factor_telegram'), 30 * MINSECS, MINSECS)); + +$settings->add(new admin_setting_configcheckbox('factor_telegram/suspend', + get_string('settings:suspend', 'factor_telegram'), + get_string('settings:suspend_help', 'factor_telegram'), 0)); diff --git a/factor/telegram/telegram.php b/factor/telegram/telegram.php new file mode 100644 index 00000000..23e9dee7 --- /dev/null +++ b/factor/telegram/telegram.php @@ -0,0 +1,99 @@ +. + +/** + * Page to revoke and disable an email code. + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +// Ignore coding standards for login check, this page does not require login. +// @codingStandardsIgnoreStart +require_once(__DIR__ . '../../../../../../config.php'); +$instanceid = required_param('instance', PARAM_INT); +$pass = optional_param('pass', '0', PARAM_INT); +$secret = optional_param('secret', 0, PARAM_INT); +// @codingStandardsIgnoreEnds + +$context = context_system::instance(); +$PAGE->set_context($context); +$url = new moodle_url('/admin/tool/mfa/factor/telegram/telegram.php', + array('instance' => $instanceid, 'pass' => $pass, 'secret' => $secret)); +$PAGE->set_url($url); +$PAGE->set_pagelayout('secure'); +$PAGE->set_title(get_string('unauthtelegram', 'factor_telegram')); +$PAGE->set_cacheable(false); +$instance = $DB->get_record('tool_mfa', array('id' => $instanceid)); + +// If pass is set, require login to force $SESSION and user, and pass for that session. +if (!empty($instance) && $pass != 0 && $secret != 0) { + if ($instance->secret != $secret) { + print_error('error:parameters'); + die; + } + require_login(); + $factor = \tool_mfa\plugininfo\factor::get_factor('email'); + $factor->set_state(\tool_mfa\plugininfo\factor::STATE_PASS); + // If wantsurl is already set in session, go to it. + if (!empty($SESSION->wantsurl)) { + redirect($SESSION->wantsurl); + } else { + redirect(new moodle_url('/')); + } +} + +$form = new \factor_telegram\form\telegram($url); + +if ($form->is_cancelled()) { + + redirect(new moodle_url('/')); +} else if ($fromform = $form->get_data()) { + if (empty($instance)) { + $message = get_string('error:badcode', 'factor_telegram'); + } else { + $user = $DB->get_record('user', array('id' => $instance->userid)); + + // Stop attacker from using email factor at all, by revoking all email until admin fixes. + $DB->set_field('tool_mfa', 'revoked', 1, array('userid' => $user->id, 'factor' => 'telegram')); + + // Remotely logout all sessions for user. + $manager = \core\session\manager::kill_user_sessions($instance->userid); + + // Log event. + $ip = $instance->createdfromip; + $useragent = $instance->label; + $event = \factor_telegram\event\unauth_telegram::unauth_telegram_event($user, $ip, $useragent); + $event->trigger(); + + // Suspend user account. + if (get_config('factor_telegram', 'suspend')) { + $DB->set_field('user', 'suspended', 1, array('id' => $userid)); + } + + $message = get_string('telegram:revokesuccess', 'factor_telegram', fullname($user)); + } +} + +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('unauthtelegram', 'factor_telegram')); +if (!empty($message)) { + echo $message; +} else { + $form->display(); +} +echo $OUTPUT->footer(); diff --git a/factor/telegram/version.php b/factor/telegram/version.php new file mode 100644 index 00000000..25578c46 --- /dev/null +++ b/factor/telegram/version.php @@ -0,0 +1,33 @@ +. + +/** + * Plugin version and other meta-data are defined here. + * + * @package factor_telegram + * @subpackage tool_mfa + * @author Jan Dageförde, Laura Troost + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2020082414; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2017051500.00; // Support back to 3.3 - Totara 12. Patches required. +$plugin->component = 'factor_telegram'; +$plugin->release = 'v0.1'; +$plugin->maturity = MATURITY_STABLE; +$plugin->dependencies = array('tool_mfa' => 2019102400); From bbea65e9e49d83a8e18c565720735dda84a09c31 Mon Sep 17 00:00:00 2001 From: Laur0r Date: Mon, 24 Aug 2020 15:32:58 +0200 Subject: [PATCH 2/9] add telegram api class --- factor/telegram/classes/factor.php | 4 ++++ factor/telegram/classes/telegram.php | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 factor/telegram/classes/telegram.php diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index d95bf496..00daa125 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -183,6 +183,8 @@ private function generate_and_telegram_code() { 'lastverified' => time(), 'revoked' => 0, ), true); + $telegram = new Telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); + $telegram->send_message(1292580991, $newcode); } else if ($record->timecreated + $duration < time()) { // Old code found. Keep id, update fields. @@ -197,6 +199,8 @@ private function generate_and_telegram_code() { 'revoked' => 0, )); $instanceid = $record->id; + $telegram = new Telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); + $telegram->send_message(1292580991, $newcode); } } diff --git a/factor/telegram/classes/telegram.php b/factor/telegram/classes/telegram.php new file mode 100644 index 00000000..e08bc807 --- /dev/null +++ b/factor/telegram/classes/telegram.php @@ -0,0 +1,19 @@ +token = $token; + } + + public function send_message($userid, $text) { + $path = "https://api.telegram.org/bot".$this->token; + file_get_contents($path."/sendmessage?chat_id=".$userid."&text=".$text); + } +} \ No newline at end of file From 4e110ba0fe5bd6642dcb61aeaefbbb4055360836 Mon Sep 17 00:00:00 2001 From: Laur0r Date: Mon, 24 Aug 2020 15:41:57 +0200 Subject: [PATCH 3/9] little bug fixes --- factor/telegram/classes/factor.php | 8 ++++---- factor/telegram/lang/en/factor_telegram.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index 00daa125..e7940bab 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -79,7 +79,7 @@ public function get_all_user_factors($user) { $records = $DB->get_records('tool_mfa', array( 'userid' => $user->id, 'factor' => $this->name, - 'label' => $user->telegram + 'label' => $user->email )); if (!empty($records)) { @@ -90,7 +90,7 @@ public function get_all_user_factors($user) { $record = array( 'userid' => $user->id, 'factor' => $this->name, - 'label' => $user->telegram, + 'label' => $user->email, 'createdfromip' => $user->lastip, 'timecreated' => time(), 'revoked' => 0, @@ -183,7 +183,7 @@ private function generate_and_telegram_code() { 'lastverified' => time(), 'revoked' => 0, ), true); - $telegram = new Telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); + $telegram = new telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); $telegram->send_message(1292580991, $newcode); } else if ($record->timecreated + $duration < time()) { @@ -199,7 +199,7 @@ private function generate_and_telegram_code() { 'revoked' => 0, )); $instanceid = $record->id; - $telegram = new Telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); + $telegram = new telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); $telegram->send_message(1292580991, $newcode); } } diff --git a/factor/telegram/lang/en/factor_telegram.php b/factor/telegram/lang/en/factor_telegram.php index 0743a21c..de5c948e 100644 --- a/factor/telegram/lang/en/factor_telegram.php +++ b/factor/telegram/lang/en/factor_telegram.php @@ -44,14 +44,14 @@ $string['event:unauthtelegram'] = 'Unauthorised telegram received'; $string['unauthtelegram'] = 'Unauthorised telegram'; $string['error:wrongverification'] = 'Incorrect verification code'; -$string['error:badcode'] = 'Code was not found. This may be an old link, a new code may have been telegramed, or the login attempt with this code was successful.'; +$string['error:badcode'] = 'Code was not found. This may be an old link, a new code may have been send to Telegram, or the login attempt with this code was successful.'; $string['error:parameters'] = 'Incorrect page parameters.'; $string['loginsubmit'] = 'Verify Code'; $string['loginskip'] = "I didn't receive a code"; $string['info'] = '

Built-in factor. Uses e-mail address mentioned in user profile for sending verification codes

'; -$string['pluginname'] = 'E-Mail Factor'; -$string['privacy:metadata'] = 'The E-Mail Factor plugin does not store any personal data'; -$string['setupfactor'] = 'E-Mail Factor setup'; +$string['pluginname'] = 'Telegram Factor'; +$string['privacy:metadata'] = 'The Telegram Factor plugin does not store any personal data'; +$string['setupfactor'] = 'Telegram Factor setup'; $string['verificationcode'] = 'Enter verification code for confirmation'; $string['verificationcode_help'] = 'Verification code has been sent to your telegram address'; $string['summarycondition'] = 'has valid telegram setup'; From 9ec3799f2eb77b47ec8167b01baf7531e99281ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Dagef=C3=B6rde?= Date: Mon, 24 Aug 2020 15:43:39 +0200 Subject: [PATCH 4/9] fix URL in renderer --- renderer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer.php b/renderer.php index 5a2115bc..496f0817 100644 --- a/renderer.php +++ b/renderer.php @@ -215,7 +215,7 @@ public function not_enough_factors() { $return = $OUTPUT->notification($notification, 'notifyerror'); // Logout button. - $url = new \moodle_url('\admin\tool\mfa\auth.php', ['logout' => 1]); + $url = new \moodle_url('/admin/tool/mfa/auth.php', ['logout' => 1]); $btn = new \single_button($url, get_string('logout'), 'post', true); $return .= $this->render($btn); From 982cfdc5834e798b3f4b596860cba65b81122ff0 Mon Sep 17 00:00:00 2001 From: Laur0r Date: Mon, 24 Aug 2020 16:16:58 +0200 Subject: [PATCH 5/9] admin setting for token --- factor/telegram/classes/factor.php | 6 ++++-- factor/telegram/lang/en/factor_telegram.php | 1 + factor/telegram/settings.php | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index e7940bab..cc82070f 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -183,7 +183,8 @@ private function generate_and_telegram_code() { 'lastverified' => time(), 'revoked' => 0, ), true); - $telegram = new telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); + $token = get_config('factor_telegram', 'telegrambottoken'); + $telegram = new telegram($token); $telegram->send_message(1292580991, $newcode); } else if ($record->timecreated + $duration < time()) { @@ -199,7 +200,8 @@ private function generate_and_telegram_code() { 'revoked' => 0, )); $instanceid = $record->id; - $telegram = new telegram("1204730014:AAEMpzxxRPRnQTLZ9eCMNgCAmBd0d9pX8iQ"); + $token = get_config('factor_telegram', 'telegrambottoken'); + $telegram = new telegram($token); $telegram->send_message(1292580991, $newcode); } } diff --git a/factor/telegram/lang/en/factor_telegram.php b/factor/telegram/lang/en/factor_telegram.php index de5c948e..99e71b49 100644 --- a/factor/telegram/lang/en/factor_telegram.php +++ b/factor/telegram/lang/en/factor_telegram.php @@ -55,3 +55,4 @@ $string['verificationcode'] = 'Enter verification code for confirmation'; $string['verificationcode_help'] = 'Verification code has been sent to your telegram address'; $string['summarycondition'] = 'has valid telegram setup'; +$string['settings:telegrambottoken'] = 'Token of Telegram bot'; \ No newline at end of file diff --git a/factor/telegram/settings.php b/factor/telegram/settings.php index 9e5c6874..218fb279 100644 --- a/factor/telegram/settings.php +++ b/factor/telegram/settings.php @@ -34,6 +34,10 @@ new lang_string('settings:weight', 'tool_mfa'), new lang_string('settings:weight_help', 'tool_mfa'), 100, PARAM_INT)); +$settings->add(new admin_setting_configtext('factor_telegram/telegrambottoken', + new lang_string('settings:telegrambottoken', 'factor_telegram'), + new lang_string('settings:telegrambottoken', 'factor_telegram'), null,PARAM_TEXT, 50)); + $settings->add(new admin_setting_configduration('factor_telegram/duration', get_string('settings:duration', 'factor_telegram'), get_string('settings:duration_help', 'factor_telegram'), 30 * MINSECS, MINSECS)); From 99d4ebc8afb3b5bbcad41cf987cd9d66df53e628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Dagef=C3=B6rde?= Date: Mon, 24 Aug 2020 16:18:23 +0200 Subject: [PATCH 6/9] prepare for user-defined telegram ids --- factor/telegram/classes/factor.php | 76 +++++++++--------------------- 1 file changed, 23 insertions(+), 53 deletions(-) diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index cc82070f..f9fb77a6 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -36,7 +36,6 @@ class factor extends object_factor_base { * {@inheritDoc} */ public function login_form_definition($mform) { - $mform->addElement('text', 'verificationcode', get_string('verificationcode', 'factor_telegram')); $mform->setType("verificationcode", PARAM_ALPHANUM); return $mform; @@ -48,7 +47,8 @@ public function login_form_definition($mform) { * {@inheritDoc} */ public function login_form_definition_after_data($mform) { - $this->generate_and_telegram_code(); + $telegramuserid = 1292580991; // TODO + $this->generate_and_telegram_code($telegramuserid); return $mform; } @@ -79,36 +79,12 @@ public function get_all_user_factors($user) { $records = $DB->get_records('tool_mfa', array( 'userid' => $user->id, 'factor' => $this->name, - 'label' => $user->email )); - - if (!empty($records)) { - return $records; - } - - // Null records returned, build new record. - $record = array( - 'userid' => $user->id, - 'factor' => $this->name, - 'label' => $user->email, - 'createdfromip' => $user->lastip, - 'timecreated' => time(), - 'revoked' => 0, - ); - $record['id'] = $DB->insert_record('tool_mfa', $record, true); - return [(object) $record]; + return $records; } - /** - * E-Mail Factor implementation. - * - * {@inheritDoc} - */ - public function has_input() { - if (self::is_ready()) { - return true; - } - return false; + public function has_setup() { + return true; } /** @@ -117,7 +93,11 @@ public function has_input() { * {@inheritDoc} */ public function get_state() { - if (!self::is_ready()) { + global $USER; + $userfactors = $this->get_active_user_factors($USER); + + // If no codes are setup then we must be neutral not unknown. + if (count($userfactors) == 0) { return \tool_mfa\plugininfo\factor::STATE_NEUTRAL; } @@ -132,16 +112,6 @@ public function get_state() { private static function is_ready() { global $DB, $USER; - if (empty($USER->email)) { //TODO - return false; - } - if (!validate_email($USER->email)) { //TODO - return false; - } - if (over_bounce_threshold($USER)) { - return false; - } - // If this factor is revoked, set to not ready. if ($DB->record_exists('tool_mfa', array('userid' => $USER->id, 'factor' => 'telegram', 'revoked' => 1))) { return false; @@ -154,19 +124,19 @@ private static function is_ready() { * * @return void */ - private function generate_and_telegram_code() { + private function generate_and_telegram_code($telegramuserid) { global $DB, $USER; - // Get instance that isnt parent email type (label check). - // This check must exclude the main singleton record, with the label as the email. + // Get instance that isnt the parent type that defines the username. + // This check must exclude the main singleton record, with the label that contains the userid. // It must only grab the record with the user agent as the label. $sql = 'SELECT * FROM {tool_mfa} WHERE userid = ? - AND factor = ? - AND NOT label = ?'; + AND factor = \'telegram\' + AND label NOT LIKE \'telegram:%\''; - $record = $DB->get_record_sql($sql, array($USER->id, 'telegram', $USER->email)); //TODO + $record = $DB->get_record_sql($sql, array($USER->id)); $duration = get_config('factor_telegram', 'duration'); $newcode = random_int(100000, 999999); @@ -185,7 +155,7 @@ private function generate_and_telegram_code() { ), true); $token = get_config('factor_telegram', 'telegrambottoken'); $telegram = new telegram($token); - $telegram->send_message(1292580991, $newcode); + $telegram->send_message($telegramuserid, $newcode); } else if ($record->timecreated + $duration < time()) { // Old code found. Keep id, update fields. @@ -202,7 +172,7 @@ private function generate_and_telegram_code() { $instanceid = $record->id; $token = get_config('factor_telegram', 'telegrambottoken'); $telegram = new telegram($token); - $telegram->send_message(1292580991, $newcode); + $telegram->send_message($telegramuserid, $newcode); } } @@ -222,8 +192,8 @@ private function check_verification_code($enteredcode) { FROM {tool_mfa} WHERE userid = ? AND factor = ? - AND NOT label = ?'; - $record = $DB->get_record_sql($sql, array($USER->id, 'telegram', $USER->email)); //TODO + AND label NOT LIKE \'telegram:%\''; + $record = $DB->get_record_sql($sql, array($USER->id, 'telegram')); //TODO if ($enteredcode == $record->secret) { if ($record->timecreated + $duration > time()) { @@ -240,11 +210,11 @@ private function check_verification_code($enteredcode) { */ public function post_pass_state() { global $DB, $USER; - // Delete all email records except base record. + // Delete all telegram records except base record. $selectsql = 'userid = ? AND factor = ? - AND NOT label = ?'; - $DB->delete_records_select('tool_mfa', $selectsql, array($USER->id, 'telegram', $USER->email)); //TODO + AND label NOT LIKE \'telegram:%\''; + $DB->delete_records_select('tool_mfa', $selectsql, array($USER->id, 'telegram')); //TODO // Update factor timeverified. parent::post_pass_state(); From 3494792a318fc8af380fa368e484370ff096f538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Dagef=C3=B6rde?= Date: Mon, 24 Aug 2020 16:59:01 +0200 Subject: [PATCH 7/9] add user setting for personal telegram id --- factor/telegram/classes/factor.php | 69 ++++++++++++++++++++- factor/telegram/lang/en/factor_telegram.php | 3 +- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index f9fb77a6..bbc0a969 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -47,7 +47,19 @@ public function login_form_definition($mform) { * {@inheritDoc} */ public function login_form_definition_after_data($mform) { - $telegramuserid = 1292580991; // TODO + global $DB, $USER; + $sql = 'SELECT * + FROM {tool_mfa} + WHERE userid = ? + AND factor = \'telegram\' + AND label LIKE \'telegram:%\''; + $record = $DB->get_record_sql($sql, array($USER->id)); + if (empty($record)) { + throw new \coding_exception('Factor has not been set up for this user!'); + } + + $telegramuserid = substr($record->label, strlen('telegram:')); + $this->generate_and_telegram_code($telegramuserid); return $mform; } @@ -231,6 +243,61 @@ public function get_no_redirect_urls() { return array($telegram); } + + /** + * TOTP Factor implementation. + * + * {@inheritDoc} + */ + public function setup_factor_form_definition($mform) { + $mform->addElement('text', 'telegramuserid', get_string('telegram:telegramuserid', 'factor_telegram')); + $mform->setType('telegramuserid', PARAM_ALPHANUM); + + return $mform; + } + + /** + * TOTP Factor implementation. + * + * {@inheritDoc} + */ + public function setup_user_factor($data) { + global $DB, $USER; + + $sql = 'SELECT * + FROM {tool_mfa} + WHERE userid = ? + AND factor = \'telegram\' + AND label LIKE \'telegram:%\''; + $record = $DB->get_record_sql($sql, array($USER->id)); + + if (!empty($data->telegramuserid)) { + $row = new \stdClass(); + $row->userid = $USER->id; + $row->factor = $this->name; + $row->label = 'telegram:'.$data->telegramuserid; + $row->timecreated = time(); + $row->createdfromip = $USER->lastip; + $row->timemodified = time(); + $row->lastverified = time(); + $row->revoked = 0; + + if (empty($record)) { + $id = $DB->insert_record('tool_mfa', $row); + } else { + $id = $row->id = $record->id; + $DB->update_record('tool_mfa', $row); + } + + $record = $DB->get_record('tool_mfa', array('id' => $id)); + $this->create_event_after_factor_setup($USER); + + return $record; + } + + return null; + } + /** * Email factor implementation. * diff --git a/factor/telegram/lang/en/factor_telegram.php b/factor/telegram/lang/en/factor_telegram.php index 99e71b49..43e7983f 100644 --- a/factor/telegram/lang/en/factor_telegram.php +++ b/factor/telegram/lang/en/factor_telegram.php @@ -55,4 +55,5 @@ $string['verificationcode'] = 'Enter verification code for confirmation'; $string['verificationcode_help'] = 'Verification code has been sent to your telegram address'; $string['summarycondition'] = 'has valid telegram setup'; -$string['settings:telegrambottoken'] = 'Token of Telegram bot'; \ No newline at end of file +$string['settings:telegrambottoken'] = 'Token of Telegram bot'; +$string['telegram:telegramuserid'] = 'Your Telegram user ID'; \ No newline at end of file From 76014906c3c04dba4cd20d02eb7540f513259889 Mon Sep 17 00:00:00 2001 From: Laur0r Date: Tue, 25 Aug 2020 09:18:46 +0200 Subject: [PATCH 8/9] delete unnecessary classes + fancy telegram message --- .../classes/event/unauth_telegram.php | 100 ------------------ factor/telegram/classes/factor.php | 26 ++--- factor/telegram/lang/en/factor_telegram.php | 17 ++- factor/telegram/telegram.php | 99 ----------------- 4 files changed, 19 insertions(+), 223 deletions(-) delete mode 100644 factor/telegram/classes/event/unauth_telegram.php delete mode 100644 factor/telegram/telegram.php diff --git a/factor/telegram/classes/event/unauth_telegram.php b/factor/telegram/classes/event/unauth_telegram.php deleted file mode 100644 index 7b69796e..00000000 --- a/factor/telegram/classes/event/unauth_telegram.php +++ /dev/null @@ -1,100 +0,0 @@ -. - -/** - * Event for unauthorised email being received from MFA. - * - * @package factor_telegram - * @subpackage tool_mfa - * @author Jan Dageförde, Laura Troost - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - - -namespace factor_telegram\event; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Event for when a user receives an unauthorised email from MFA. - * - * @property-read array $other { - * Extra information about event. - * } - * - * @package factor_email - * @author Peter Burnett - * @copyright Catalyst IT - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -class unauth_telegram extends \core\event\base { - /** - * Create instance of event. - * - * @param stdClass $user the User object of the User who passed all MFA factor checks. - * @param string $ip the ip address the unauthorised email came from. - * @param string $useragent the browser fingerpring the unauthorised email came from. - * - * @return user_passed_mfa the user_passed_mfa event - * - * @throws \coding_exception - */ - public static function unauth_telegram_event($user, $ip, $useragent) { - - $data = array( - 'relateduserid' => null, - 'context' => \context_user::instance($user->id), - 'other' => array ( - 'userid' => $user->id, - 'ip' => $ip, - 'useragent' => $useragent - ) - ); - - return self::create($data); - } - - /** - * Init method. - * - * @return void - */ - protected function init() { - $this->data['crud'] = 'r'; - $this->data['edulevel'] = self::LEVEL_OTHER; - } - - /** - * Returns description of what happened. - * - * @return string - */ - public function get_description() { - return "The user with id '{$this->other['userid']}' made an unauthorised login attempt using telegram verification from - IP '{$this->other['ip']}' with browser agent '{$this->other['useragent']}'."; - } - - /** - * Return localised event name. - * - * @return string - * @throws \coding_exception - */ - public static function get_name() { - return get_string('event:unauthtelegram', 'factor_telegram'); - } -} diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index bbc0a969..567b77df 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -137,7 +137,7 @@ private static function is_ready() { * @return void */ private function generate_and_telegram_code($telegramuserid) { - global $DB, $USER; + global $DB, $USER, $CFG; // Get instance that isnt the parent type that defines the username. // This check must exclude the main singleton record, with the label that contains the userid. @@ -167,7 +167,11 @@ private function generate_and_telegram_code($telegramuserid) { ), true); $token = get_config('factor_telegram', 'telegrambottoken'); $telegram = new telegram($token); - $telegram->send_message($telegramuserid, $newcode); + $a = new \stdClass(); + $a->sitename = 'Moodle'; // TODO + $a->code = $newcode; + $message = get_string('telegram:message', 'factor_telegram', $a); + $telegram->send_message($telegramuserid, $message); } else if ($record->timecreated + $duration < time()) { // Old code found. Keep id, update fields. @@ -184,7 +188,11 @@ private function generate_and_telegram_code($telegramuserid) { $instanceid = $record->id; $token = get_config('factor_telegram', 'telegrambottoken'); $telegram = new telegram($token); - $telegram->send_message($telegramuserid, $newcode); + $a = new \stdClass(); + $a->sitename = 'Moodle'; // TODO + $a->code = $newcode; + $message = get_string('telegram:message', 'factor_telegram', $a); + $telegram->send_message($telegramuserid, $message); } } @@ -232,18 +240,6 @@ public function post_pass_state() { parent::post_pass_state(); } - /** - * Email factor implementation. - * Email page must be safe to authorise session from link. - * - * {@inheritDoc} - */ - public function get_no_redirect_urls() { - $telegram = new \moodle_url('/admin/tool/mfa/factor/telegram/telegram.php'); - return array($telegram); - } - - /** * TOTP Factor implementation. * diff --git a/factor/telegram/lang/en/factor_telegram.php b/factor/telegram/lang/en/factor_telegram.php index 43e7983f..75bd0baf 100644 --- a/factor/telegram/lang/en/factor_telegram.php +++ b/factor/telegram/lang/en/factor_telegram.php @@ -28,32 +28,31 @@ Alternatively you can click {$a->link} from the same device to authorise this session.'; $string['telegram:ipinfo'] = 'IP Information'; $string['telegram:originatingip'] = 'This login request was made from \'{$a}\''; +$string['telegram:message'] = 'This is your login code for {$a->sitename}: {$a->code}'; $string['telegram:uadescription'] = 'Browser identity for this request:'; $string['telegram:browseragent'] = 'The browser details for this request are: \'{$a}\''; $string['telegram:revokelink'] = 'If this wasn\'t you, follow {$a} to stop this login attempt.'; $string['telegram:geoinfo'] = 'This request appears to have originated from approximately {$a->city}, {$a->country}.'; $string['telegram:link'] = 'this link'; $string['telegram:revokesuccess'] = 'This code has been successfully revoked. All sessions for {$a} have been ended. - telegram will not be usable as a factor until account security has been verified.'; -$string['telegram:accident'] = 'If you did not request this telegram, click continue to attempt to invalidate the login attempt. + Telegram will not be usable as a factor until account security has been verified.'; +$string['telegram:accident'] = 'If you did not request this Telegram code, click continue to attempt to invalidate the login attempt. If you clicked this link by accident, click cancel, and no action will be taken.'; $string['settings:duration'] = 'Validity duration'; $string['settings:duration_help'] = 'The period of time that the code is valid.'; -$string['settings:suspend'] = 'Suspend unauthorised accounts'; -$string['settings:suspend_help'] = 'Check this to suspend user accounts if an unauthorised telegram verification is received.'; -$string['event:unauthtelegram'] = 'Unauthorised telegram received'; -$string['unauthtelegram'] = 'Unauthorised telegram'; $string['error:wrongverification'] = 'Incorrect verification code'; $string['error:badcode'] = 'Code was not found. This may be an old link, a new code may have been send to Telegram, or the login attempt with this code was successful.'; $string['error:parameters'] = 'Incorrect page parameters.'; $string['loginsubmit'] = 'Verify Code'; +$string['settings:suspend_help'] = ''; +$string['settings:suspend'] = ''; $string['loginskip'] = "I didn't receive a code"; -$string['info'] = '

Built-in factor. Uses e-mail address mentioned in user profile for sending verification codes

'; +$string['info'] = '

Built-in factor. Uses Telegram user id set in user profile for sending verification codes

'; $string['pluginname'] = 'Telegram Factor'; $string['privacy:metadata'] = 'The Telegram Factor plugin does not store any personal data'; $string['setupfactor'] = 'Telegram Factor setup'; $string['verificationcode'] = 'Enter verification code for confirmation'; -$string['verificationcode_help'] = 'Verification code has been sent to your telegram address'; -$string['summarycondition'] = 'has valid telegram setup'; +$string['verificationcode_help'] = 'Verification code has been sent to your Telegram account'; +$string['summarycondition'] = 'has valid Telegram setup'; $string['settings:telegrambottoken'] = 'Token of Telegram bot'; $string['telegram:telegramuserid'] = 'Your Telegram user ID'; \ No newline at end of file diff --git a/factor/telegram/telegram.php b/factor/telegram/telegram.php deleted file mode 100644 index 23e9dee7..00000000 --- a/factor/telegram/telegram.php +++ /dev/null @@ -1,99 +0,0 @@ -. - -/** - * Page to revoke and disable an email code. - * - * @package factor_telegram - * @subpackage tool_mfa - * @author Jan Dageförde, Laura Troost - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -// Ignore coding standards for login check, this page does not require login. -// @codingStandardsIgnoreStart -require_once(__DIR__ . '../../../../../../config.php'); -$instanceid = required_param('instance', PARAM_INT); -$pass = optional_param('pass', '0', PARAM_INT); -$secret = optional_param('secret', 0, PARAM_INT); -// @codingStandardsIgnoreEnds - -$context = context_system::instance(); -$PAGE->set_context($context); -$url = new moodle_url('/admin/tool/mfa/factor/telegram/telegram.php', - array('instance' => $instanceid, 'pass' => $pass, 'secret' => $secret)); -$PAGE->set_url($url); -$PAGE->set_pagelayout('secure'); -$PAGE->set_title(get_string('unauthtelegram', 'factor_telegram')); -$PAGE->set_cacheable(false); -$instance = $DB->get_record('tool_mfa', array('id' => $instanceid)); - -// If pass is set, require login to force $SESSION and user, and pass for that session. -if (!empty($instance) && $pass != 0 && $secret != 0) { - if ($instance->secret != $secret) { - print_error('error:parameters'); - die; - } - require_login(); - $factor = \tool_mfa\plugininfo\factor::get_factor('email'); - $factor->set_state(\tool_mfa\plugininfo\factor::STATE_PASS); - // If wantsurl is already set in session, go to it. - if (!empty($SESSION->wantsurl)) { - redirect($SESSION->wantsurl); - } else { - redirect(new moodle_url('/')); - } -} - -$form = new \factor_telegram\form\telegram($url); - -if ($form->is_cancelled()) { - - redirect(new moodle_url('/')); -} else if ($fromform = $form->get_data()) { - if (empty($instance)) { - $message = get_string('error:badcode', 'factor_telegram'); - } else { - $user = $DB->get_record('user', array('id' => $instance->userid)); - - // Stop attacker from using email factor at all, by revoking all email until admin fixes. - $DB->set_field('tool_mfa', 'revoked', 1, array('userid' => $user->id, 'factor' => 'telegram')); - - // Remotely logout all sessions for user. - $manager = \core\session\manager::kill_user_sessions($instance->userid); - - // Log event. - $ip = $instance->createdfromip; - $useragent = $instance->label; - $event = \factor_telegram\event\unauth_telegram::unauth_telegram_event($user, $ip, $useragent); - $event->trigger(); - - // Suspend user account. - if (get_config('factor_telegram', 'suspend')) { - $DB->set_field('user', 'suspended', 1, array('id' => $userid)); - } - - $message = get_string('telegram:revokesuccess', 'factor_telegram', fullname($user)); - } -} - -echo $OUTPUT->header(); -echo $OUTPUT->heading(get_string('unauthtelegram', 'factor_telegram')); -if (!empty($message)) { - echo $message; -} else { - $form->display(); -} -echo $OUTPUT->footer(); From 2519fe93db82c213ec5a3ce5fd1992bfb66e09f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Dagef=C3=B6rde?= Date: Mon, 24 Aug 2020 17:28:06 +0200 Subject: [PATCH 9/9] start improving the docs --- factor/telegram/classes/factor.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/factor/telegram/classes/factor.php b/factor/telegram/classes/factor.php index 567b77df..16b51be3 100644 --- a/factor/telegram/classes/factor.php +++ b/factor/telegram/classes/factor.php @@ -31,7 +31,7 @@ class factor extends object_factor_base { /** - * Telegram Factor implementation. + * User input for the generated code. * * {@inheritDoc} */ @@ -42,12 +42,14 @@ public function login_form_definition($mform) { } /** - * E-Mail Factor implementation. + * Generate a token that is sent to the user via Telegram. * * {@inheritDoc} */ public function login_form_definition_after_data($mform) { global $DB, $USER; + + // Get the user's Telegram ID from the tool_mfa configuration. $sql = 'SELECT * FROM {tool_mfa} WHERE userid = ? @@ -60,12 +62,13 @@ public function login_form_definition_after_data($mform) { $telegramuserid = substr($record->label, strlen('telegram:')); + // Send a random code to the user on Telegram. $this->generate_and_telegram_code($telegramuserid); return $mform; } /** - * E-Mail Factor implementation. + * Validate the entered code. * * {@inheritDoc} */ @@ -90,7 +93,7 @@ public function get_all_user_factors($user) { $records = $DB->get_records('tool_mfa', array( 'userid' => $user->id, - 'factor' => $this->name, + 'factor' => $this->name, // TODO look for prefix )); return $records; } @@ -125,6 +128,7 @@ private static function is_ready() { global $DB, $USER; // If this factor is revoked, set to not ready. + // Looking for prefix is not necessary: A single record with "revoked" is sufficient. if ($DB->record_exists('tool_mfa', array('userid' => $USER->id, 'factor' => 'telegram', 'revoked' => 1))) { return false; } @@ -213,7 +217,7 @@ private function check_verification_code($enteredcode) { WHERE userid = ? AND factor = ? AND label NOT LIKE \'telegram:%\''; - $record = $DB->get_record_sql($sql, array($USER->id, 'telegram')); //TODO + $record = $DB->get_record_sql($sql, array($USER->id, 'telegram')); if ($enteredcode == $record->secret) { if ($record->timecreated + $duration > time()) { @@ -234,7 +238,7 @@ public function post_pass_state() { $selectsql = 'userid = ? AND factor = ? AND label NOT LIKE \'telegram:%\''; - $DB->delete_records_select('tool_mfa', $selectsql, array($USER->id, 'telegram')); //TODO + $DB->delete_records_select('tool_mfa', $selectsql, array($USER->id, 'telegram')); // Update factor timeverified. parent::post_pass_state();