From 5068968581202530d4aa4b973347b33a660bd40c Mon Sep 17 00:00:00 2001 From: "eapl.mx" Date: Thu, 23 Nov 2023 15:56:48 -0600 Subject: [PATCH 1/6] Implement support for TOTP Add TOTP.php and allow password or TOTP in session.php --- libs/TOTP.php | 166 ++++++++++++++++++++++++++++++++++++++++++++++ libs/session.php | 22 ++++-- partials/base.php | 4 +- views/login.php | 18 +++-- 4 files changed, 193 insertions(+), 17 deletions(-) create mode 100644 libs/TOTP.php diff --git a/libs/TOTP.php b/libs/TOTP.php new file mode 100644 index 0000000..1ef0173 --- /dev/null +++ b/libs/TOTP.php @@ -0,0 +1,166 @@ +\n"; + + for ($currentWindow = -$window; $currentWindow <= $window; $currentWindow++) { + $time = $timeSlice + $currentWindow; + $generatedCode = generateTOTP($secret, $digits, $time); + #echo "$time $generatedCode
\n"; + + if ($generatedCode === $enteredCodeInt) { + return true; // Code is valid within the window + } + } + + return false; // Code is not valid +} + +function generateTOTP($secret, $digits = 6, $timeSlice = null) { + if ($timeSlice === null) { + $timeSlice = floor(time() / 30); + } + + $secret = base32Decode($secret); + $timeSlice = pack('N*', 0) . pack('N*', $timeSlice); + + $hash = hash_hmac('sha1', $timeSlice, $secret, true); + $offset = ord($hash[19]) & 0xf; + + $otp = ( + (ord($hash[$offset + 0]) & 0x7f) << 24 | + (ord($hash[$offset + 1]) & 0xff) << 16 | + (ord($hash[$offset + 2]) & 0xff) << 8 | + (ord($hash[$offset + 3]) & 0xff) + ); + + #var_dump($otp); + #echo "
\n"; + + // When digits is 10, the padding was giving a wrong OTP + // Just return the calculated value + if ($digits === 10) { + return $otp; + } + + $otp = $otp % pow(10, $digits); + return str_pad($otp, $digits, '0', STR_PAD_LEFT); +} + +function base32Decode($base32) { + $base32chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; + $base32charsFlipped = array_flip(str_split($base32chars)); + $paddingChar = '='; + $paddingCharCount = 0; + + if (strpos($base32, $paddingChar) !== false) { + $paddingCharCount = substr_count($base32, $paddingChar); + } + + $allowedValues = array(6, 4, 3, 1, 0); + + if (!in_array($paddingCharCount, $allowedValues)) { + return false; + } + + for ($i = 0; $i < 4; ++$i) { + if ($paddingCharCount == $allowedValues[$i] && + substr($base32, -$allowedValues[$i]) != str_repeat($paddingChar, $allowedValues[$i]) + ) { + return false; + } + } + + $base32 = str_replace($paddingChar, '', $base32); + $base32 = str_split($base32); + $binaryString = ''; + + foreach ($base32 as $char) { + if (!isset($base32charsFlipped[$char])) { + return false; // Invalid character found + } + $binaryString .= sprintf('%05b', $base32charsFlipped[$char]); + } + + $length = strlen($binaryString); + $offset = 0; + $binaryData = ''; + + while ($offset < $length) { + $binaryChunk = substr($binaryString, $offset, 8); + + if (strlen($binaryChunk) < 8) { + $binaryChunk = str_pad($binaryChunk, 8, '0', STR_PAD_RIGHT); + } + + $decimalChunk = bindec($binaryChunk); + $binaryData .= pack('C', $decimalChunk); + $offset += 8; + } + + return $binaryData; +} + +function base32Encode($input) { + $base32Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; + $base32String = ''; + $position = 0; + $carry = 0; + foreach (str_split($input) as $byte) { + $carry |= ord($byte) << $position; + $position += 8; + while ($position >= 5) { + $base32String .= $base32Chars[$carry & 31]; + $carry >>= 5; + $position -= 5; + } + } + if ($position > 0) { + if ($carry & 31) { + $base32String .= $base32Chars[$carry & 31]; + } + } + return $base32String; +} + +function generateRandomSecret($length = 32) { + // https://medium.com/@nicola88/two-factor-authentication-with-totp-ccc5f828b6df + $bytes = random_bytes($length); + $base32 = base32Encode($bytes); + + return substr($base32, 0, $length); +} + +# Examples of usage (To move somewhere else) +/* +$randomSecret = generateRandomSecret(); +echo "Random Secret Key: $randomSecret
\n"; + +$secret = 'K3OBZ7XPR6T4PTNXSNCQ'; +$enteredCode = '123456'; +$digits = 6; +if (isset($_GET['c']) && isset($_GET['s'])) { + $enteredCode = $_GET['c']; + $secret = $_GET['s']; + $isCodeValid = verifyTOTP($secret, $digits, $enteredCode); + + if ($isCodeValid) { + echo "Code $enteredCode is valid!
"; + } else { + echo "Code $enteredCode is invalid!
"; + } +} + +$code = generateTOTP($secret); +echo "TOTP code: $code
\n"; + +$code = generateTOTP($secret, 8); +echo "TOTP code: $code
\n"; +*/ diff --git a/libs/session.php b/libs/session.php index 28ffa4a..bb9f9fc 100644 --- a/libs/session.php +++ b/libs/session.php @@ -1,18 +1,30 @@ - +
-

Enter password:

+

Enter password or TOTP

-
+

From 8272067347ca292247529181b95b5afe098260c5 Mon Sep 17 00:00:00 2001 From: sorenpeter Date: Fri, 26 Jan 2024 17:17:20 +0100 Subject: [PATCH 2/6] Working progress bar using some JS --- twtxt_template.txt | 34 ---------------------------- views/load_twt_files.php | 49 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 38 deletions(-) delete mode 100644 twtxt_template.txt diff --git a/twtxt_template.txt b/twtxt_template.txt deleted file mode 100644 index 330a06d..0000000 --- a/twtxt_template.txt +++ /dev/null @@ -1,34 +0,0 @@ -# | |___ _| |___ _| |_ -# | __\ \ /\ / / __\ \/ / __| -# | |_ \ V V /| |_ > <| |_ -# \__| \_/\_/ \__/_/\_\\__| -# -# Twtxt is an open, distributed and decentralized microblogging platform -# for hackers and friends that uses raw text files, easy to read by humans, -# and with common protocols and free and open. -# -# Using twtxt-php from: https://github.com/eapl-gemugami/twtxt-php -# Know more about twtxt here: https://github.com/buckket/twtxt -# Using the following extensions: -# https://github.com/eapl-gemugami/twtxt-php/blob/master/docs/02-metadata-extension.md -# -# nick = timeline -# url = http://example.com/timeline/twtxt.txt -# avatar = http://example.com/timeline/avatar.png -# emoji = 👾 -# link = -# lang = -# description = -# discovery = -# -# following = 123 -# follow = eapl.me https://eapl.me/twtxt.txt -# follow = eapl.mx https://eapl.mx/twtxt.txt -# follow = lyse https://lyse.isobeef.org/twtxt.txt -# follow = prologic https://twtxt.net/user/prologic/twtxt.txt -# follow = sorenpeter http://darch.dk/twtxt.txt -# follow = stigatle https://yarn.stigatle.no/user/stigatle/twtxt.txt -# follow = thecanine https://twtxt.net/user/thecanine/twtxt.txt -#~~~# - -2023-09-10T18:55:27+02:00 Hello twtxt world! diff --git a/views/load_twt_files.php b/views/load_twt_files.php index 81abab6..d183c6f 100644 --- a/views/load_twt_files.php +++ b/views/load_twt_files.php @@ -44,6 +44,7 @@ $fileContent = mb_convert_encoding($fileContent, 'UTF-8'); $fileLines = explode("\n", $fileContent); $twtFollowingList = []; + foreach ($fileLines as $currentLine) { if (str_starts_with($currentLine, '#')) { if (!is_null(getDoubleParameter('follow', $currentLine))) { @@ -54,13 +55,53 @@ foreach ($fileLines as $currentLine) { # Load all the files # Save a flag to know it's loading files in the background +/* foreach ($twtFollowingList as $following) { echo "Updating: $following[1]
\n"; #ob_flush(); + flush(); updateCachedFile($following[1]); } -echo 'Finished'; -#ob_flush(); +*/ +//echo 'Finished'; +//ob_flush(); + +//header('Location: /'); +//exit(); + +/* from: https://github.com/w3shaman/php-progress-bar */ + +echo '
'; + +echo '
'; + + +$i = 1; +foreach ($twtFollowingList as $following) { + $total = count($twtFollowingList); + // Calculate the percentation + $percent = intval($i/$total * 100)."%"; + + // Javascript for updating the progress bar and information + echo ''; + + +// This is for the buffer achieve the minimum size in order to flush data + + echo "Updating: $following[1]"." (".$i."/".$total.")
\n"; + updateCachedFile($following[1]); + +// Send output to browser immediately + flush(); + $i++; +} + +echo 'Finished'; + + +// Tell user that the process is completed +echo ''; -header('Location: /'); -exit(); From c1579a27a6555aaf55eb512a8ecbb24bc41c1916 Mon Sep 17 00:00:00 2001 From: sorenpeter Date: Fri, 26 Jan 2024 18:34:47 +0100 Subject: [PATCH 3/6] Make it pretty using HTML5 progress element --- views/load_twt_files.php | 59 +++++++++++++--------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/views/load_twt_files.php b/views/load_twt_files.php index d183c6f..68acd17 100644 --- a/views/load_twt_files.php +++ b/views/load_twt_files.php @@ -33,16 +33,18 @@ if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) { die('Not a valid URL'); } -echo "Loading URL: $url
\n
\n"; -#ob_flush(); +echo '
'; +echo ''; + +ob_flush(); const DEBUG_TIME_SECS = 300; const PRODUCTION_TIME_SECS = 5; $fileContent = getCachedFileContentsOrUpdate($url, PRODUCTION_TIME_SECS); $fileContent = mb_convert_encoding($fileContent, 'UTF-8'); - $fileLines = explode("\n", $fileContent); +// Build Following List $twtFollowingList = []; foreach ($fileLines as $currentLine) { @@ -53,55 +55,32 @@ foreach ($fileLines as $currentLine) { } } -# Load all the files -# Save a flag to know it's loading files in the background -/* -foreach ($twtFollowingList as $following) { - echo "Updating: $following[1]
\n"; - #ob_flush(); - flush(); - updateCachedFile($following[1]); -} -*/ -//echo 'Finished'; -//ob_flush(); - -//header('Location: /'); -//exit(); - -/* from: https://github.com/w3shaman/php-progress-bar */ - -echo '
'; - -echo '
'; +/* Progress bar based on: https://github.com/w3shaman/php-progress-bar */ $i = 1; +$total = count($twtFollowingList); foreach ($twtFollowingList as $following) { - $total = count($twtFollowingList); - // Calculate the percentation - $percent = intval($i/$total * 100)."%"; + $float = $i/$total; + $percent = intval($float * 100)."%"; // Javascript for updating the progress bar and information echo ''; + document.getElementById("refreshLabel").innerHTML = "Updating: '.$following[1].' ('.$i.'/'.$total.')"; + document.getElementById("refreshProgress").value = "'.$float.'"; + document.getElementById("refreshProgress").innerHTML = "'.$percent.'"; + '; - -// This is for the buffer achieve the minimum size in order to flush data + updateCachedFile($following[1]); - echo "Updating: $following[1]"." (".$i."/".$total.")
\n"; - updateCachedFile($following[1]); - -// Send output to browser immediately - flush(); + ob_flush(); // Send output to browser immediately $i++; } -echo 'Finished'; - // Tell user that the process is completed -echo ''; +echo ''; + +//header('Location: /'); +exit(); From 2d88c1b0515c5ae2b42725f0930d9411839fcba4 Mon Sep 17 00:00:00 2001 From: sorenpeter Date: Mon, 29 Jan 2024 20:55:50 +0100 Subject: [PATCH 4/6] Some CSS work --- index.php | 3 +- style.css => libs/timeline.css | 20 ++++++++ partials/header.php | 10 ++-- views/load_twt_files.php | 13 ++++- views/refresh.php | 92 ++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 8 deletions(-) rename style.css => libs/timeline.css (95%) create mode 100644 views/refresh.php diff --git a/index.php b/index.php index 8ab3ed3..3efde7b 100644 --- a/index.php +++ b/index.php @@ -30,7 +30,8 @@ $routes = [ '/new' => 'new_twt.php', '/add' => 'add_feed.php', '/following' => 'following.php', - '/refresh' => 'load_twt_files.php', + //'/refresh' => 'load_twt_files.php', + '/refresh' => 'refresh.php', '/login' => 'login.php', '/logout' => 'logout.php', '/profile' => 'profile.php', diff --git a/style.css b/libs/timeline.css similarity index 95% rename from style.css rename to libs/timeline.css index af3fac8..1701d1d 100644 --- a/style.css +++ b/libs/timeline.css @@ -238,6 +238,26 @@ nav.pagnation { padding: 0.5rem 0; } + +/* === REFRESH === */ + +#refreshLabel { +} + +#refreshInfo { + font-weight: bold; +} + +#refreshURL { + display: block; +} + +#refreshCounter { + float: right; +} + + +/* === FOOTER === */ footer { border-top: thin solid grey; margin-top: 1rem; diff --git a/partials/header.php b/partials/header.php index e1109bd..5187cee 100644 --- a/partials/header.php +++ b/partials/header.php @@ -4,12 +4,14 @@ $profile = getTwtsFromTwtxtString($config['public_txt_url']); ?> + - - + + + <?= $title ?> @@ -42,6 +44,4 @@ $profile = getTwtsFromTwtxtString($config['public_txt_url']); -
- - +
\ No newline at end of file diff --git a/views/load_twt_files.php b/views/load_twt_files.php index 68acd17..96ce792 100644 --- a/views/load_twt_files.php +++ b/views/load_twt_files.php @@ -2,9 +2,13 @@ # Gets the followers from an URL and then gets all the Followers twtxt.txt files # Intended to be run in the background +/* require_once("libs/session.php"); // TODO: Move all to base.php require_once('libs/twtxt.php'); require_once('libs/hash.php'); +*/ + +require_once("partials/base.php"); $config = parse_ini_file('private/config.ini'); @@ -13,6 +17,7 @@ if (!isset($_SESSION['password'])) { exit(); } + $max_execution_time = intval($config['max_execution_time']); if ($max_execution_time < 1) { $max_execution_time = 1; @@ -20,9 +25,13 @@ if ($max_execution_time < 1) { ini_set('max_execution_time', $max_execution_time); -#ob_start(); +//ob_start(); -$config = parse_ini_file('private/config.ini'); +//require_once 'partials/header.php'; +//ob_flush(); + + +//$config = parse_ini_file('private/config.ini'); $url = $config['public_txt_url']; if (!empty($_GET['url'])) { diff --git a/views/refresh.php b/views/refresh.php new file mode 100644 index 0000000..56c2a2d --- /dev/null +++ b/views/refresh.php @@ -0,0 +1,92 @@ + + +

+ Loading feeds followed by: + + (1 of 10) +

+ + + + + document.getElementById("refreshInfo").innerHTML = " + Updating: + '.preg_replace('(^https?://)', '', $following[1]).' + ('.$i.' of '.$total.') + "; + document.getElementById("refreshProgress").value = "'.$float.'"; + document.getElementById("refreshProgress").innerHTML = "'.$percent.'"; + '; + + updateCachedFile($following[1]); + ob_flush(); // Send output to browser immediately + flush(); + $i++; +} + +// Tell user that the process is completed +echo ''; + From bd6a4b262d27ba78dc2d31dd5e19e3bf8d1cdf53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?s=C3=B8renpeter?= Date: Mon, 29 Jan 2024 21:58:27 +0100 Subject: [PATCH 5/6] Styling refresh --- libs/timeline.css | 2 +- views/refresh.php | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/libs/timeline.css b/libs/timeline.css index 1701d1d..a96a3e6 100644 --- a/libs/timeline.css +++ b/libs/timeline.css @@ -246,10 +246,10 @@ nav.pagnation { #refreshInfo { font-weight: bold; +/* display: block;*/ } #refreshURL { - display: block; } #refreshCounter { diff --git a/views/refresh.php b/views/refresh.php index 56c2a2d..f2bf9d6 100644 --- a/views/refresh.php +++ b/views/refresh.php @@ -18,11 +18,10 @@ include 'partials/header.php'; ?>

- Loading feeds followed by: - - (1 of 10) + Loading feeds followed by: + +

- document.getElementById("refreshInfo").innerHTML = "Updating feed from:"'; + foreach ($twtFollowingList as $following) { //ob_start(); $float = $i/$total; $percent = intval($float * 100)."%"; - + $feed = $following[1]; + //$feed = preg_replace('(^https?://)', '', $feed); + //$feed = $following[0].'@'. parse_url($following[1], PHP_URL_HOST); + $feed = $following[0].' ('.$following[1].')'; + // Javascript for updating the progress bar and information echo ''; @@ -86,7 +88,9 @@ foreach ($twtFollowingList as $following) { // Tell user that the process is completed echo ''; From 313a8c9a4c058394dea6d1af7e9bb3e8d2bb538a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?s=C3=B8renpeter?= Date: Wed, 31 Jan 2024 14:17:16 +0100 Subject: [PATCH 6/6] Fixed CSS for refresh --- views/refresh.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/views/refresh.php b/views/refresh.php index f2bf9d6..1eb7eea 100644 --- a/views/refresh.php +++ b/views/refresh.php @@ -18,7 +18,7 @@ include 'partials/header.php'; ?>

- Loading feeds followed by: + Loading feeds followed by:

@@ -88,8 +88,8 @@ foreach ($twtFollowingList as $following) { // Tell user that the process is completed echo '';