diff --git a/SECURITY.md b/SECURITY.md index 611f392..5d703a8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,4 +7,4 @@ Examples: `master`, `develop`, `admin-panel` ## Reporting a Vulnerability -Please mail me@smileycreations15.com about the security issue. +Please mail `hi [at] semisol [dot] dev` about the security issue. diff --git a/includes/common/db.php b/includes/common/db.php index 0440d9c..57b9211 100644 --- a/includes/common/db.php +++ b/includes/common/db.php @@ -3,6 +3,7 @@ namespace MediaWiki\Extension\ScratchOAuth2\Common; use Database; +use MediaWiki\MediaWikiServices; class SOA2DB { protected static $dbw; @@ -24,7 +25,12 @@ public static function dbr() { } protected static function dbFactory() { global $wgSOA2DBtype, $wgSOA2DBserver, $wgSOA2DBuser, $wgSOA2DBpassword, $wgSOA2DBname, $wgSOA2DBprefix; - if (!$wgSOA2DBtype) return wfGetDB; + if (!$wgSOA2DBtype) { + $loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer(); + return static function ( $index ) use ( $loadBalancer ) { + return $loadBalancer->getConnection( $index ); + }; + }; $type = $wgSOA2DBtype; $params = [ 'host' => $wgSOA2DBserver, @@ -42,24 +48,25 @@ protected static function dbFactory() { public static function saveUser( int $user_id, string $username ) { $values = [ 'user_id' => $user_id, - 'user_name' => strtolower($username) + 'user_name' => strtolower($username), + 'user_name_cased' => $username ]; self::dbw()->upsert( 'soa2_scratchers', $values, - array_keys($values), $values + 'user_id', $values ); } public static function getUserById( int $user_id ) { return self::dbr()->selectRow( 'soa2_scratchers', - ['user_id', 'user_name'], + ['user_id', 'user_name', 'user_name_cased'], ['user_id' => $user_id] ); } public static function getUserByName( string $username ) { return self::dbr()->selectRow( 'soa2_scratchers', - ['user_id', 'user_name'], + ['user_id', 'user_name', 'user_name_cased'], ['user_name' => strtolower($username)] ); } diff --git a/includes/common/hooks.php b/includes/common/hooks.php index 3be9e52..a84df5e 100644 --- a/includes/common/hooks.php +++ b/includes/common/hooks.php @@ -2,6 +2,10 @@ namespace MediaWiki\Extension\ScratchOAuth2; use DatabaseUpdater; +use MediaWiki\Extension\ScratchOAuth2\Common\SOA2Login; + +require_once __DIR__ . "/consts.php"; +require_once __DIR__ . "/login.php"; class SOA2Hooks { public static function schemaUpdates( DatabaseUpdater $updater ) { @@ -39,6 +43,29 @@ public static function schemaUpdates( DatabaseUpdater $updater ) { 'soa2_redirect_uris', $sql_dir . '/redirect_uris_key.sql' ); + $updater->addExtensionField( + 'soa2_scratchers', + 'user_name_cased', + $sql_dir . '/cased_usernames.sql' + ); + $updater->addExtensionUpdate( [ + 'MediaWiki\Extension\ScratchOAuth2\SOA2Hooks::fetchCasedUsernames' + ] ); return true; } + + public static function fetchCasedUsernames( DatabaseUpdater $updater ) { + // add cased usernames for those who don't have them + $dbw = $updater->getDB(); + $res = $dbw->select( + 'soa2_scratchers', + ['user_id', 'user_name'], + ['user_name_cased' => null] + ); + foreach ($res as $row) { + $username = $row->user_name; + $updater->output( "Fetching cased username for $username\n" ); + SOA2Login::api( $username ); + } + } } \ No newline at end of file diff --git a/includes/common/login.php b/includes/common/login.php index e5f5bbc..ed563f4 100644 --- a/includes/common/login.php +++ b/includes/common/login.php @@ -21,18 +21,26 @@ public static function gen_code( $session ) { return $session->get( 'soa2_scratch_code' ); } /** - * Get the data needed to complete a login. - * @param string $username the username to get the codes for + * Get and save user data from the API. + * @param string $username the username to get the data for */ - public static function codes( string $username ) { - global $wgRequest; + public static function api( string $username ) { // get user data from API $user = json_decode(file_get_contents(sprintf( SOA2_USERS_API, urlencode($username))), true); if (!$user) return null; - // save user data - $username = $user['username']; + // save it to DB, possibly updating the case SOA2DB::saveUser( $user['id'], $user['username'] ); + return $user; + } + /** + * Get the data needed to complete a login. + * @param string $username the username to get the codes for + */ + public static function codes( string $username ) { + global $wgRequest; + $user = self::api( $username ); + $username = $user['username']; // actually do the code generation $session = $wgRequest->getSession(); $session->persist(); diff --git a/includes/common/users.php b/includes/common/users.php index b38cae0..165ea2b 100644 --- a/includes/common/users.php +++ b/includes/common/users.php @@ -25,11 +25,12 @@ public static function makeProfileLink($username) { /** * Get a username by ID * @param int $user_id the user ID + * @param bool $cased if false, return the username in lowercase (default true) * @return string|null the username, or null if not found */ - public static function getName( int $user_id ) { + public static function getName( int $user_id, bool $cased = true ) { $user = SOA2DB::getUserById( $user_id ); - return $user ? $user->user_name : null; + return $user ? ($cased ? $user->user_name_cased : $user->user_name) : null; } public static function getID( string $user_name ) { $user = SOA2DB::getUserByName( $user_name ); diff --git a/sql/cased_usernames.sql b/sql/cased_usernames.sql new file mode 100644 index 0000000..d8c923e --- /dev/null +++ b/sql/cased_usernames.sql @@ -0,0 +1,6 @@ +BEGIN; + +-- Scratch username, case sensitive +ALTER TABLE /*_*/soa2_scratchers ADD COLUMN IF NOT EXISTS user_name_cased varchar(20) binary UNIQUE; + +COMMIT; \ No newline at end of file