From d0cab7054fd3eca5492fb7bd5922da6782ce9d02 Mon Sep 17 00:00:00 2001 From: flashwave Date: Wed, 20 Nov 2024 02:43:47 +0000 Subject: [PATCH] Switched to public API for authentication and a horrible device auth implementation for unsecured connections. --- config/config.php | 4 + lang/en.php | 2 + public/css/Black.ajaxchat.css | 4 +- public/css/Blue.ajaxchat.css | 3 +- public/css/Halext.ajaxchat.css | 8 +- public/css/Nico.ajaxchat.css | 4 +- public/css/chatlogin.css | 7 +- public/css/mio.css | 18 +++-- public/css/mobile.ajaxchat.css | 3 +- public/css/mobiledev.ajaxchat.css | 4 +- public/css/yuuno.css | 29 +++++-- public/js/chat.js | 4 +- src/AJAXChatTemplate.php | 6 +- src/CustomAJAXChat.php | 128 +++++++++++++++++++++--------- src/SockChatAuth.php | 52 ------------ template/legacyLogin.html | 8 +- 16 files changed, 169 insertions(+), 115 deletions(-) delete mode 100644 src/SockChatAuth.php diff --git a/config/config.php b/config/config.php index 52dead8..c1f8244 100644 --- a/config/config.php +++ b/config/config.php @@ -50,6 +50,10 @@ $config['flashiiUrl']['feedback'] = 'https://flashii.net/forum'; $config['flashiiUrl']['changelog'] = 'https://flashii.net/changelog'; $config['flashiiUrl']['rules'] = 'https://flashii.net/info/rules'; $config['flashiiUrl']['contact'] = 'https://flashii.net/info/contact'; +$config['flashiiId']['api'] = ''; +$config['flashiiId']['id'] = ''; +$config['flashiiId']['clientId'] = ''; +$config['flashiiId']['clientSecret'] = ''; if(is_file(AJAX_CHAT_PATH . '/config/config-db.php')) include_once AJAX_CHAT_PATH . '/config/config-db.php'; diff --git a/lang/en.php b/lang/en.php index e7db74a..12beaf0 100644 --- a/lang/en.php +++ b/lang/en.php @@ -119,3 +119,5 @@ $lang['logsTime'] = 'Time'; $lang['logsSearch'] = 'Search'; $lang['logsPrivateChannels'] = 'Private Channels'; $lang['logsPrivateMessages'] = 'Private Messages'; +$lang['fidAuthzRequestFailed'] = 'Could not request authorization code.'; +$lang['fidAuthzTokenFailed'] = 'Could not complete authorization request, please try again.'; diff --git a/public/css/Black.ajaxchat.css b/public/css/Black.ajaxchat.css index df8e554..3278e3c 100644 --- a/public/css/Black.ajaxchat.css +++ b/public/css/Black.ajaxchat.css @@ -17,6 +17,8 @@ color:#f0f0f0; border: 1px solid #808080; background-image: linear-gradient(to bottom, #222, #000); + background-image: -moz-linear-gradient(to bottom, #222, #000); + background-image: -webkit-linear-gradient(top, #222, #000); } #content select, #loginForm select, #loginForm input, #content textarea { background-color:#000; @@ -95,4 +97,4 @@ background-color:#212121; color:#FFF; } -} \ No newline at end of file +} diff --git a/public/css/Blue.ajaxchat.css b/public/css/Blue.ajaxchat.css index 5c3c3b5..62986a5 100644 --- a/public/css/Blue.ajaxchat.css +++ b/public/css/Blue.ajaxchat.css @@ -20,6 +20,7 @@ color:#f0f0f0; border: 1px solid #808080; background-image: linear-gradient(to bottom, #002545, #000); + background-image: -moz-linear-gradient(to bottom, #002545, #000); background-image: -webkit-linear-gradient(top, #002545, #000); } #content select, #loginForm select, #loginForm input, #content textarea { @@ -103,4 +104,4 @@ background-color:#0D355D; color:#FFF; } -} \ No newline at end of file +} diff --git a/public/css/Halext.ajaxchat.css b/public/css/Halext.ajaxchat.css index dbf92bb..2fe5680 100644 --- a/public/css/Halext.ajaxchat.css +++ b/public/css/Halext.ajaxchat.css @@ -18,7 +18,9 @@ #loginContent { background-color: #000000; - background-image: -linear-gradient(to bottom, #4c3b52, #000000); + background-image: linear-gradient(to bottom, #4c3b52, #000000); + background-image: -moz-linear-gradient(to bottom, #4c3b52, #000000); + background-image: -webkit-linear-gradient(top, #4c3b52, #000000); color: #999999; } #loginContent h1 { @@ -42,6 +44,8 @@ #content { background-color: #000000; background-image: linear-gradient(to bottom, #4c3b52, #000000); + background-image: -moz-linear-gradient(to bottom, #4c3b52, #000000); + background-image: -webkit-linear-gradient(top, #4c3b52, #000000); color: #999999; } #content h1 { @@ -105,4 +109,4 @@ #content #settingsContainer #settingsList input.playback { background: url('../images/playback.png') no-repeat; } -} \ No newline at end of file +} diff --git a/public/css/Nico.ajaxchat.css b/public/css/Nico.ajaxchat.css index 7cc5343..23f3f62 100644 --- a/public/css/Nico.ajaxchat.css +++ b/public/css/Nico.ajaxchat.css @@ -17,6 +17,7 @@ color:#f0f0f0; border: 1px solid #808080; background-image: linear-gradient(to bottom, #110033, #000000); + background-image: -moz-linear-gradient(to bottom, #110033, #000000); background-image: -webkit-linear-gradient(top, #110033, #000000); } #loginContent #loginButton { @@ -24,6 +25,7 @@ color:#f0f0f0; border: 1px solid #808080; background-image: linear-gradient(to bottom, #110033, #000000); + background-image: -moz-linear-gradient(to bottom, #110033, #000000); background-image: -webkit-linear-gradient(top, #110033, #000000); } #loginContent input { @@ -133,4 +135,4 @@ #content .cmod { color: #0033FF; }*/ -} \ No newline at end of file +} diff --git a/public/css/chatlogin.css b/public/css/chatlogin.css index f9631e8..cf395b9 100644 --- a/public/css/chatlogin.css +++ b/public/css/chatlogin.css @@ -15,7 +15,10 @@ h3 { font-size: 15px; padding: 2px; margin: 10px; - background: linear-gradient(180deg, #900, #600) #700; + background-color: #700; + background-image: linear-gradient(to bottom, #900, #600); + background-image: -moz-linear-gradient(to bottom, #900, #600); + background-image: -webkit-linear-gradient(top, #900, #600); } div.copyright { @@ -66,4 +69,4 @@ a { a:hover { text-shadow: 0px 0px 1em #F1F1F1; -} \ No newline at end of file +} diff --git a/public/css/mio.css b/public/css/mio.css index b895c52..1f88b71 100644 --- a/public/css/mio.css +++ b/public/css/mio.css @@ -14,7 +14,11 @@ body { margin: 0px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; - background: linear-gradient(180deg, #C2AFFE, #FBEEFF) repeat-x scroll center top #FBEEFF; + background-color: #fbeeff; + background-image: linear-gradient(to bottom, #c2affe, #fbeeff); + background-image: -moz-linear-gradient(to bottom, #c2affe, #fbeeff); + background-image: -webkit-linear-gradient(top, #c2affe, #fbeeff); + background-repeat: repeat-x; background-size: auto 200px; text-align: center; } @@ -23,7 +27,7 @@ img.logo { height: 150px; width: 450px; border: 0px; - background: url('https://static.flash.moe/logos/logo.png') no-repeat scroll left top transparent; + background: url('//static.flash.moe/logos/logo.png') no-repeat scroll left top transparent; background-size: cover; } @@ -424,7 +428,7 @@ div.ucp_avatar_cont { height: 23px; width: 23px; border: 0px; - background: url('https://static.flash.moe/images/window-sprite.png') no-repeat scroll 0px 0px transparent; + background: url('//static.flash.moe/images/window-sprite.png') no-repeat scroll 0px 0px transparent; } .maxbutton { @@ -432,7 +436,7 @@ div.ucp_avatar_cont { height: 23px; width: 23px; border: 0px; - background: url('https://static.flash.moe/images/window-sprite.png') no-repeat scroll 0px -23px transparent; + background: url('//static.flash.moe/images/window-sprite.png') no-repeat scroll 0px -23px transparent; } .minbutton { @@ -440,7 +444,7 @@ div.ucp_avatar_cont { height: 23px; width: 23px; border: 0px; - background: url('https://static.flash.moe/images/window-sprite.png') no-repeat scroll 0px -46px transparent; + background: url('//static.flash.moe/images/window-sprite.png') no-repeat scroll 0px -46px transparent; } .donate-btn { @@ -448,7 +452,7 @@ div.ucp_avatar_cont { height: 26px; width: 90px; border: 0px; - background: url('https://static.flash.moe/images/donate-btn.png') no-repeat scroll 0px 0px transparent; + background: url('//static.flash.moe/images/donate-btn.png') no-repeat scroll 0px 0px transparent; } div.topLeftBar { @@ -848,4 +852,4 @@ div#recaptcha_image { } .news-comments-container { margin: 5px auto 0px; -} \ No newline at end of file +} diff --git a/public/css/mobile.ajaxchat.css b/public/css/mobile.ajaxchat.css index eb40fc2..912c444 100644 --- a/public/css/mobile.ajaxchat.css +++ b/public/css/mobile.ajaxchat.css @@ -357,6 +357,7 @@ color:#f0f0f0; border: 1px solid #808080; background-image: linear-gradient(to bottom, #222, #000); + background-image: -moz-linear-gradient(to bottom, #222, #000); background-image: -webkit-linear-gradient(top, #222, #000); } #content select, #loginForm select, #loginForm input, #content textarea { @@ -436,4 +437,4 @@ background-color:#212121; color:#FFF; } -} \ No newline at end of file +} diff --git a/public/css/mobiledev.ajaxchat.css b/public/css/mobiledev.ajaxchat.css index 0ecd7a1..be03842 100644 --- a/public/css/mobiledev.ajaxchat.css +++ b/public/css/mobiledev.ajaxchat.css @@ -331,6 +331,8 @@ color: #f0f0f0; border: 1px solid #808080; background-image: linear-gradient(to bottom, #222, #000); + background-image: -moz-linear-gradient(to bottom, #222, #000); + background-image: -webkit-linear-gradient(top, #222, #000); } #content select, #loginForm select, #loginForm input, #content textarea { background-color: #000; @@ -407,4 +409,4 @@ #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { background-color: #212121; color: #FFF; -} \ No newline at end of file +} diff --git a/public/css/yuuno.css b/public/css/yuuno.css index dc16060..a04a7ef 100644 --- a/public/css/yuuno.css +++ b/public/css/yuuno.css @@ -15,7 +15,11 @@ html { } body { font: 12px/20px Verdana, sans-serif; - background: linear-gradient(180deg, #C2AFFE, #FBEEFF) no-repeat scroll left top #FBEEFF; + background-color: #fbeeff; + background-repeat: no-repeat; + background-image: linear-gradient(to bottom, #c2affe, #fbeeff); + background-image: -moz-linear-gradient(to bottom, #c2affe, #fbeeff); + background-image: -webkit-linear-gradient(top, #c2affe, #fbeeff); background-size: cover; color: #000; height: 100%; @@ -118,7 +122,7 @@ a.default:active { } a.gotop { display: inline-block; - background: url('https://static.flash.moe/images/arrow.png') #111; + background: url('//static.flash.moe/images/arrow.png') #111; color: #FFF; width: 60px; height: 60px; @@ -192,7 +196,9 @@ a.gotop:active { /* Site Header Styling */ .header { text-align: center; - background: linear-gradient(180deg, #C2AFFE, #CCBAFE); + background-image: linear-gradient(to bottom, #c2affe, #ccbafe); + background-image: -moz-linear-gradient(to bottom, #c2affe, #ccbafe); + background-image: -webkit-linear-gradient(top, #c2affe, #ccbafe); box-shadow: 0 0 5px #8364A1; } /*.header .logo { @@ -349,7 +355,10 @@ a.gotop:active { width: 100%; padding-top: 10px; padding-bottom: 30px; - background: linear-gradient(180deg, #9475B2 0%, #FBEEFF 20%, #C2AFFE 100%) #C2AFFE; + background-color: #c2affe; + background-image: linear-gradient(to bottom, #9475B2 0%, #FBEEFF 20%, #C2AFFE 100%); + background-image: -moz-linear-gradient(to bottom, #9475B2 0%, #FBEEFF 20%, #C2AFFE 100%); + background-image: -webkit-linear-gradient(top, #9475B2 0%, #FBEEFF 20%, #C2AFFE 100%); position: absolute; bottom: 0; } @@ -537,7 +546,7 @@ a.gotop:active { font-weight: 700; font-size: 20px; color: #306; - background: linear-gradient(90deg, rgba(148,117,178,.7), rgba(148,117,178,0)) #C2AFFE; + background: linear-gradient(90deg, rgba(148,117,178,.7), rgba(148,117,178,0)); border-radius: 2px; } .content-right .head, @@ -558,7 +567,10 @@ a.gotop:active { text-align: center; border-radius: 5px; font-weight: 100; - background: linear-gradient(180deg, #874399, #35245E) #874399; + background-color: #874399; + background-image: linear-gradient(to bottom, #874399, #35245E); + background-image: -moz-linear-gradient(to bottom, #874399, #35245E); + background-image: -webkit-linear-gradient(top, #874399, #35245E); transition: text-shadow .25s; color: #FFF; font-size: 16px; @@ -570,7 +582,10 @@ a.gotop:active { cursor: pointer; } .content-right .registerbutton { - background: linear-gradient(180deg, #874399, #35245E) #874399; + background-color: #874399; + background-image: linear-gradient(to bottom, #874399, #35245E); + background-image: -moz-linear-gradient(to bottom, #874399, #35245E); + background-image: -webkit-linear-gradient(top, #874399, #35245E); } .button.profileOption { width: auto !important; diff --git a/public/js/chat.js b/public/js/chat.js index 38e845c..70a7ae0 100644 --- a/public/js/chat.js +++ b/public/js/chat.js @@ -2410,7 +2410,7 @@ var ajaxChat = { replaceCommandWhois: function(textParts) { return '' - + this.lang['whois'].replace(/%s/, textParts[1]) + ' ' + textParts[2] @@ -3002,4 +3002,4 @@ var ajaxChat = { return true; } -} \ No newline at end of file +} diff --git a/src/AJAXChatTemplate.php b/src/AJAXChatTemplate.php index a929512..e4a08e1 100644 --- a/src/AJAXChatTemplate.php +++ b/src/AJAXChatTemplate.php @@ -303,7 +303,11 @@ HTML; function getErrorMessageTags() { $errorMessages = ''; foreach($this->ajaxChat->getInfoMessages('error') as $error) { - $errorMessages .= '

'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang($error)).'

'; + $html = $this->ajaxChat->getLang($error); + if($error !== 'errorInvalidUser') + $html = $this->ajaxChat->htmlEncode($html); + + $errorMessages .= '

'.$html.'

'; } return $errorMessages; } diff --git a/src/CustomAJAXChat.php b/src/CustomAJAXChat.php index d9e2e6f..5a0f010 100644 --- a/src/CustomAJAXChat.php +++ b/src/CustomAJAXChat.php @@ -9,52 +9,108 @@ namespace AJAXChat; +use Flashii\{FlashiiClient,FlashiiUrls}; +use Flashii\Credentials\{BasicCredentials,BearerCredentials,MisuzuCredentials}; + class CustomAJAXChat extends AJAXChat { // Returns an associative array containing userName, userID and userRole // Returns null if login is invalid function getValidLoginUserData() { - if(empty($_COOKIE['msz_auth'])) { - header('Location: ' . $this->getConfig('flashiiAuth', 'login')); - exit; - } - - $userInfo = SockChatAuth::attempt( - $this->getConfig('flashiiAuth', 'verify'), - $this->getConfig('flashiiSecret'), - (string)filter_input(INPUT_COOKIE, 'msz_auth') + // TODO: this sucks + $urls = new FlashiiUrls( + (fn() => (($url = $this->getConfig('flashiiId', 'api')) === '' ? FlashiiUrls::PROD_API_URL : $url))(), + (fn() => (($url = $this->getConfig('flashiiId', 'id')) === '' ? FlashiiUrls::PROD_ID_URL : $url))() ); - if($userInfo->success) { - // Check if we have a valid registered user: + if(filter_has_var(INPUT_SERVER, 'HTTPS')) { + $authToken = trim((string)filter_input(INPUT_COOKIE, 'msz_auth')); + if($authToken === '') { + header('Location: ' . $this->getConfig('flashiiAuth', 'login')); + exit; + } - $chatUser = [ - 'userID' => $userInfo->user_id, - 'userName' => $userInfo->username, - 'userRole' => AJAX_CHAT_GUEST, - ]; - - // sock chat auth doesn't actually return role ids lol - if($userInfo->colour_raw === 0xEE9400) - $chatUser['userRole'] = DONATOR; - elseif($userInfo->colour_raw === 0x0099FF) - $chatUser['userRole'] = CMOD; - elseif($userInfo->colour_raw === 0x7353C4) - $chatUser['userRole'] = PURPLE; - elseif($userInfo->colour_raw === 0x9E8DA7) - $chatUser['userRole'] = BOTS; - elseif($userInfo->rank >= 10) - $chatUser['userRole'] = AJAX_CHAT_ADMIN; - elseif($userInfo->rank >= 5) - $chatUser['userRole'] = AJAX_CHAT_MODERATOR; - elseif($userInfo->rank >= 1) - $chatUser['userRole'] = AJAX_CHAT_USER; - - return $chatUser; + $flashii = new FlashiiClient('AJAX Chat', new MisuzuCredentials($authToken), $urls); } else { - // Guest users: - return $this->getGuestUser(); + $flashii = new FlashiiClient('AJAX Chat', new BasicCredentials( + $this->getConfig('flashiiId', 'clientId'), + $this->getConfig('flashiiId', 'clientSecret') + ), $urls); + + $doPoll = true; + $expiresIn = (int)$this->getSessionVar('fidDeviceExpiresIn'); + if($expiresIn < time()) { + $this->regenerateSessionID(); + + $doPoll = false; + $request = $flashii->oauth2()->requestAuthorize('identify'); + if($request instanceof \Flashii\OAuth2\OAuth2AuthorizationRequest) { + $this->setSessionVar('fidDeviceCode', $request->getDeviceCode()); + $this->setSessionVar('fidDeviceUserCode', $request->getUserCode()); + $this->setSessionVar('fidDeviceExpiresIn', time() + $request->getExpiresIn()); + $this->setSessionVar('fidDevicePollInterval', $request->getInterval()); + $this->setSessionVar('fidDeviceUri', $request->getVerificationUri()); + $this->setSessionVar('fidDeviceUriFull', $request->getVerificationUriComplete()); + } else + $this->addInfoMessage('fidAuthzRequestFailed'); + } + + $deviceCode = $this->getSessionVar('fidDeviceCode'); + if(!empty($deviceCode)) { + if($doPoll) { + $token = $flashii->oauth2()->tokenWithDeviceCode($deviceCode); + if($token instanceof \Flashii\OAuth2\OAuth2Token) + $flashii = $flashii->forkWithAccessToken($token->getAccessToken()); + else { + if($token->getCode() !== 'slow_down') { + $this->setSessionVar('fidDeviceExpiresIn', 0); + $this->regenerateSessionID(); + } + + $this->addInfoMessage('fidAuthzTokenFailed'); + } + } + + $this->getLang(); // load language + $this->_lang['errorInvalidUser'] = sprintf( + $this->_lang['fidPoll'] ?? 'You need to approve the login attempt! If your browser supports HTTPS
click here, or go to %s on a device that does and enter %s and press the Login button again.', + $this->getSessionVar('fidDeviceUriFull'), + $this->getSessionVar('fidDeviceUri'), + $this->getSessionVar('fidDeviceUserCode') + ); + } } + + // Check if we have a valid registered user: + $userInfo = $flashii->v1()->me(); + + // Guest users: + if($userInfo === null) + return $this->getGuestUser(); + + $chatUser = [ + 'userID' => $userInfo->getId(), + 'userName' => $userInfo->getName(), + ]; + + if($userInfo->hasRole('admin')) + $chatUser['userRole'] = AJAX_CHAT_ADMIN; + elseif($userInfo->hasRole('gmod')) + $chatUser['userRole'] = AJAX_CHAT_MODERATOR; + elseif($userInfo->hasRole('dev')) + $chatUser['userRole'] = PURPLE; + elseif($userInfo->hasRole('bot')) + $chatUser['userRole'] = BOTS; + elseif($userInfo->hasRole('tenshi')) + $chatUser['userRole'] = DONATOR; + elseif($userInfo->hasRole('og') || $userInfo->getId() === '72') + $chatUser['userRole'] = CMOD; // OGs are blue here i guess lol + elseif($userInfo->getRank() > 0) + $chatUser['userRole'] = AJAX_CHAT_USER; + else + $chatUser['userRole'] = AJAX_CHAT_GUEST; + + return $chatUser; } // Store the channels the current user has access to diff --git a/src/SockChatAuth.php b/src/SockChatAuth.php deleted file mode 100644 index 233d1c7..0000000 --- a/src/SockChatAuth.php +++ /dev/null @@ -1,52 +0,0 @@ - false, - CURLOPT_FAILONERROR => false, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_HEADER => false, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query([ - 'method' => $method, - 'token' => $cookie, - 'ipaddr' => $_SERVER['REMOTE_ADDR'], - ], '', '&', PHP_QUERY_RFC3986), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TCP_FASTOPEN => true, - CURLOPT_CONNECTTIMEOUT => 2, - CURLOPT_MAXREDIRS => 2, - CURLOPT_PROTOCOLS => CURLPROTO_HTTPS, - CURLOPT_TIMEOUT => 5, - CURLOPT_USERAGENT => 'AJAX Chat', - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/x-www-form-urlencoded', - 'X-SharpChat-Signature: ' . $signature, - ], - ]); - $userInfo = json_decode(curl_exec($login)); - curl_close($login); - } - - if(empty($userInfo->success)) { - $userInfo = new stdClass; - $userInfo->success = false; - $userInfo->user_id = 0; - $userInfo->username = 'Anonymous'; - $userInfo->colour_raw = 0x40000000; - $userInfo->rank = 0; - $userInfo->hierarchy = 0; - $userInfo->perms = 0; - } - - return $userInfo; - } -} diff --git a/template/legacyLogin.html b/template/legacyLogin.html index 9181f68..b65da4c 100644 --- a/template/legacyLogin.html +++ b/template/legacyLogin.html @@ -23,7 +23,9 @@ div.toplogo { font-size: 30px; - background-image: linear-gradient(180deg, #190015/*#2F426C#FF2400*/, transparent); + background-image: linear-gradient(to bottom, #190015/*#2F426C#FF2400*/, transparent); + background-image: -moz-linear-gradient(to bottom, #190015/*#2F426C#FF2400*/, transparent); + background-image: -webkit-linear-gradient(top, #190015/*#2F426C#FF2400*/, transparent); padding-left: 10px; padding-right: 10px; font-family: "Century Gothic", Gothic, sans-serif; @@ -72,11 +74,15 @@ div.topmenu a:hover { text-shadow: 0px 0px 8px #F1F1F1; background-image: linear-gradient(to bottom, #8800BB, transparent); + background-image: -moz-linear-gradient(to bottom, #8800BB, transparent); + background-image: -webkit-linear-gradient(top, #8800BB, transparent); } div.topmenu a:active { text-shadow: 0px 0px 8px #0042FF; background-image: linear-gradient(to bottom, #440077, transparent); + background-image: -moz-linear-gradient(to bottom, #440077, transparent); + background-image: -webkit-linear-gradient(top, #440077, transparent); } [STYLE_SHEETS/]