track
a.php?p=email => period
a.php?u=month&h=HHHHHHHH => update deadline
a.php?g=l~k => zip
a.php?time=month&key=password + POST file => upload
a.php?s=mel@domain.org => form
a.php?s=mel@domain.org&t=password + [action] => manage account
action: a=login a=logout a=r[on|off] a=p[minute|hour|day|week|month|quarter]
*/
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
define ('JIRAFEAU_ROOT', dirname (__FILE__) . '/');
require (JIRAFEAU_ROOT . 'lib/settings.php');
require (JIRAFEAU_ROOT . 'lib/functions.php');
require (JIRAFEAU_ROOT . 'lib/lang.php');
define ('VAR_TOKENS', $cfg ['var_root'].'tokens/');
define ('VAR_TRACKS', $cfg ['var_root'].'tracks/');
define ('VAR_PERIOD', $cfg ['var_root'].'period/');
define ('VAR_FAKE', $cfg ['var_root'].'fake/');
define ('VAR_PRIVATE', $cfg ['var_root'].'private/');
define ('MAX_VALID_UPLOAD_TIME', 60);
define ('TOKEN_USE_LIMIT', "-2 hours");
define ('TOKEN_LOGIN_LIMIT', "-15 minutes");
define ('TOKEN_LOGOUT_LIMIT', "-8 hours");
define ('DEFAULT_PERIOD', "month");
define ('E_BAD_ARCHIVE_NAME', 'Bad archive name format');
define ('E_CREATE_ZIP', "Impossible de créer l'archive.");
define ('E_OPEN_ZIP', "Impossible d'ouvrir l'archive.");
define ('M_BAD_KEY', "Mauvaise clef pour ");
define ('M_BAD_SENDER_NAME', 'Votre mèl est incorrect');
define ('M_BAD_TOKEN', "Vous n'utilisez pas le bon jeton (consultez votre messagerie).");
define ('M_TOO_LONG_BEFORE_LOGGED', "Jeton de connexion trop ancien.");
define ('M_TOO_LONG_LOGGED', "Temps de connexion dépassé.");
define ('M_EMAIL_CONTENT', "Bonjour,
Ceci est un message automatique, car vous venez de cliquer sur une demande de consultation de vos pièces jointes.
!!! Si vous n'êtes pas à l'origine de cette demande, ne cliquez sur aucun lien de ce message. !!!
Le lien de connexion suivant est valable 15 minutes.
___LINK___
Vous pouvez signaler des abus auprès de Kaz en faisant suivre ce message qui contient les traces de son émetteur (___IP___, ___DATE___).
Bonne navigation.
.");
define ('M_DOWNLOAD', "Télécharger");
define ('M_UPDATE', "Prolonger");
define ('M_EMAIL_SUBJECT', "Lien de consultation des envois de pièces jointes.");
define ('M_FILE', " fichier.");
define ('M_FILES', " fichiers.");
define ('M_FILES_NOT_FOUND', " fichiers sont expirés.");
define ('M_FILES_RENAMED', " fichiers renommés.");
define ('M_FILE_NOT_FOUND', " fichier est expiré.");
define ('M_FILE_RENAMED', " fichier renommé.");
define ('M_INTRO_FORM', "Quelles sont les informations me concernant ?");
define ('M_MEL', "votre mèl");
define ('M_NO_FILENAME', 'SansNom');
define ('M_NO_SENDER', 'kaz-');
define ('M_NEW_ATTACHEMENT_DIRNAME', "nouveau");
define ('M_OLD_ATTACHEMENT_DIRNAME', "ancien");
define ('M_SEND', "Connexion");
define ('M_LOGOUT', 'Deconnecter');
define ('M_REFRESH', 'Actualiser');
define ('M_LOGOUT_TOKEN', "Vous n'êtes plus connecté.");
define ('M_SEND_TOKEN', "
Vous allez recevoir un lien d'accès temporaire à vos données.
"); define ('M_WELCOME', "Informations concernant le compte : ___SENDER___
(page actualisée à ___DATE___)
' . $msg . '
error:".$line."
"; $error = true; break; } } return $error ? [] : $archive; } // ======================================== function getFileName ($hash) { $p = s2p ($hash); return VAR_FILES.$p.$hash; } function getTimeFile ($hash) { $f = getFileName ($hash); return file_exists ($f) ? filemtime ($f) : 0; } function valideTime ($t1, $t2) { global $message; return abs ($t1 - $t2) < MAX_VALID_UPLOAD_TIME; } // ======================================== /** Update link * @param $link the link's name (hash) * @param $update_period the period (i.e in : "month") */ function updateLink ($link_name, $link, $maxLimit) { $time_max = $link ['time']; if ($time_max < 0 || $maxLimit < $time_max) return $time_max; $time_more = $maxLimit + JIRAFEAU_MINUTE; $link ['time'] = $time_more; $link_tmp_name = VAR_LINKS . $link ['hash'] . rand (0, 10000) . '.tmp'; $handle = fopen ($link_tmp_name, 'w'); fwrite ($handle, $link ['file_name'] .NL. $link ['mime_type'] .NL. $link ['file_size'] .NL. $link ['key'] .NL. $link ['time'] .NL. $link ['hash'] .NL. $link ['onetime'] .' '.JIRAFEAU_MONTH . ' '. JIRAFEAU_DAY .NL. $link ['upload_date'] .NL. $link ['ip'] .NL. $link ['link_code'] .NL. $link ['crypted']); fclose ($handle); $link_file = VAR_LINKS . s2p ("$link_name") . $link_name; rename ($link_tmp_name, $link_file); return $time_more; } // ======================================== function sendEMail ($receiver, $receiver_name, $subject, $body_string){ try { // SERVER SETTINGS $mail = new PHPMailer (true); $mail->isSMTP (); $mail->Host = 'smtp'; $mail->SMTPAuth = false; $mail->SMTPAutoTLS = false; $mail->SMTPSecure = "none"; $mail->Port = 25; $mail->charSet = "UTF-8"; $mail->ContentType = 'text/html'; //Recipients (change this for every project) $mail->setFrom ('no-reply@kaz.local', ''); $mail->addAddress ($receiver, $receiver_name); //Content $mail->isHTML (true); $mail->Subject = $subject; $mail->Body = $body_string; //send the message, check for errors if (!$mail->send ()) { //echo 'Mailer Error: ' . $mail->ErrorInfo; return 0; } else { //echo 'Message sent!'; return 1; } } catch (Exception $e) { return 0; } } // ======================================== function cleanToken () { if (!file_exists (VAR_TOKENS)) mkdir (VAR_TOKENS, 0755); $d = dir (VAR_TOKENS); $oldest = strtotime (TOKEN_USE_LIMIT); foreach (glob (VAR_TOKENS."*") as $file) { if (filemtime ($file) <= $oldest) unlink ($file); } } function rmToken ($sender) { if (!$sender) return; if (file_exists (VAR_TOKENS.$sender)) unlink (VAR_TOKENS.$sender); } function setToken ($sender) { if (!$sender) return; $token = md5 (rand ()); if (file_put_contents (VAR_TOKENS.$sender, T_CREATE.": ".time ().NL.T_TOKEN.": ".$token.NL)) return $token; return false; } function setLoggedToken ($sender, $token) { if (!$sender || !$token) return; file_put_contents (VAR_TOKENS.$sender, T_CREATE.": ".time ().NL.T_TOKEN.": ".$token.NL.T_LOGGED.": ok".NL); } function getTokenVar ($sender, $varName) { if (!$sender) return; if (!file_exists (VAR_TOKENS.$sender)) return false; $content = file_get_contents (VAR_TOKENS.$sender); if (preg_match ("/\b".$varName.":\s*([^\s]+)\n/", $content, $matches)) return $matches [1]; return false; } function getToken ($sender) { return getTokenVar ($sender, T_TOKEN,); } function getCreateToken ($sender) { return getTokenVar ($sender, T_CREATE); } function getLoggedToken ($sender) { return getTokenVar ($sender, T_LOGGED); } function getTimeToken ($sender) { if (!$sender || !file_exists (VAR_TOKENS.$sender)) return false; return filemtime (VAR_TOKENS.$sender); } // ======================================== if ($doUpload) { $maxtime = time ()+period2seconds ($_REQUEST ['time']); $key = isset ($_REQUEST ['key']) ? $_REQUEST ['key'] : ''; $ip = $_SERVER ['HTTP_X_REAL_IP']; // XXX $res = jirafeau_upload ( $_FILES['file'], isset ($_POST ['one_time_download']), $key, $maxtime, $ip, $cfg['enable_crypt'], $cfg['link_name_length'], $cfg['file_hash'] ); if (! count ($res ['error']) || $res['error']['has_error']) $content = 'Error 6 ' . $res['error']['why']; else $content = $res ['link'].NL.$res ['delete_link'].NL; header ('HTTP/1.0 200 OK'); header ('Content-Length: ' . strlen ($content)); header ('Content-Type: text/plain'); echo $content; exit; } // ======================================== if ($doUpdate) { $maxTime = time ()+period2seconds ($_REQUEST [A_UPDATE]); // XXX issue ")" if (!preg_match ('/([0-9a-zA-Z_-]+)\)?$/', $_REQUEST [A_HASH], $matches)) returnError (t ('FILE_404')); $linkName = $matches [1]; $link = jirafeau_get_link ($linkName); if (count ($link) == 0) returnError (t ('FILE_404')); $time = updateLink ($linkName, $link, $maxTime); $content = '' . $time . NL; if (isKazArchive ($link)) { $archiveInfo = readArchiveFromLink ($l); if (count ($archiveInfo)) { foreach ([T_OLD, T_NEW] as $cat) if (isset ($archiveInfo [$cat])) foreach ($archiveInfo [$cat] as [$linkName, $cryptKey]) updateLink ($linkName, jirafeau_get_link ($linkName), $maxTime); } } header ('HTTP/1.0 200 OK'); header ('Content-Length: ' . strlen ($content)); header ('Content-Type: text/plain'); echo $content; exit; } $sender = ''; $senderError = false; if (isset ($_REQUEST [A_SENDER]) && !empty ($_REQUEST [A_SENDER])) { // XXX //if (!preg_match ("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/i", $_REQUEST [A_SENDER])) if (!preg_match ("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/i", $_REQUEST [A_SENDER])) $senderError=true; else { cleanToken (); $sender = $_REQUEST [A_SENDER]; } } // ======================================== if ($doDownload) { // check archive exist $couple = explode ("~", $_REQUEST [A_GET], 2); if (count ($couple) == 0) returnError (E_BAD_ARCHIVE_NAME); $linkName = $couple [0]; if (!$linkName || !preg_match ('/[0-9a-zA-Z_-]+$/', $linkName)) returnError (E_BAD_ARCHIVE_NAME); $cryptKey = count ($couple) == 2 ? $couple [1] : ""; $link = jirafeau_get_link ($linkName); if (count ($link) == 0) returnError (t ('FILE_404')); $key = $link ['key']; if ($key && (empty ($cryptKey) || $key != $cryptKey)) returnError (t ('BAD_PSW')); $archiveInfo = readArchiveFromLink ($link); // check entries $archiveContent = []; $modif = false; $singleName = []; foreach ([T_OLD, T_NEW] as $cat) if (isset ($archiveInfo [$cat])) foreach ($archiveInfo [$cat] as [$linkName, $cryptKey]) { $link = jirafeau_get_link ($linkName); if (count ($link) == 0) { if (isset ($archiveContent [T_NOT_FOUND])) ++$archiveContent [T_NOT_FOUND]; else $archiveContent [T_NOT_FOUND] = 1; $modif = true; continue; } $key = $link ['key']; if ($key && (empty ($cryptKey) || $key != $cryptKey)) { if (isset ($archiveContent [T_BAD_PASW])) ++$archiveContent [T_BAD_PASW]; else $archiveContent [T_BAD_PASW] = 1; $modif = true; continue; } $srcName = $dstName = ($link ['file_name'] ? $link ['file_name'] : M_NO_FILENAME); if (in_array ($srcName, $singleName)) for ($i = 0; $i < 10000; ++$i) { $dstName = sprintf ("%s-%2d", $srcName, $i); if (!in_array ($dstName, $singleName)) { if (isset ($archiveContent [T_RENAME])) ++$archiveContent [T_RENAME]; else $archiveContent [T_RENAME] = 1; $modif = true; break; } } $singleName [] = $dstName; $archiveContent [$cat][T_ENTRIES][] = [T_HASH => $link ['hash'], T_FILENAME => $dstName, T_CRYPT_KEY => $cryptKey, T_CRYPTED => $link ['crypted']]; } // build zip $dirname = M_NO_SENDER.(isset ($archiveInfo [T_TIME]) && !empty ($archiveInfo [T_TIME])) ? $archiveInfo [T_TIME] : date ("Y-m-d-H:i:s"); $dirname = str_replace (":", "_", $dirname); $tmpFileName = tempnam (sys_get_temp_dir (), $dirname."-"); $zip = new ZipArchive; if (!$zip) returnError (E_CREATE_ZIP); if ($zip->open ($tmpFileName.T_ZIP_EXT, ZipArchive::CREATE) !== TRUE) returnError (E_OPEN_ZIP); // create info if ($modif) { $info = ''; if (isset ($archiveContent [T_NOT_FOUND])) $info .= $archiveContent [T_NOT_FOUND]. ($archiveContent [T_NOT_FOUND] ? M_FILE_NOT_FOUND : M_FILES_NOT_FOUND).NL; if (isset ($archiveContent [T_BAD_PASW])) $info .= M_BAD_KEY. $archiveContent [T_BAD_PASW]. ($archiveContent [T_BAD_PASW] ? M_FILE : M_FILES).NL; if (isset ($archiveContent [T_RENAME])) $info .= $archiveContent [T_RENAME]. ($archiveContent [T_RENAME] ? M_FILE_RENAMED : M_FILES_RENAMED).NL; $zip->addFromString ($dirname.T_WARNING_FILENAME, $info); } foreach ([T_OLD, T_NEW] as $cat) if (isset ($archiveContent [$cat])) { $subdir = $dirname . "-".($cat == T_NEW ? M_NEW_ATTACHEMENT_DIRNAME : M_OLD_ATTACHEMENT_DIRNAME); foreach ($archiveContent [$cat][T_ENTRIES] as $entry) { $p = s2p ($entry [T_HASH]); if ($entry [T_CRYPTED]) { $m = mcrypt_module_open ('rijndael-256', '', 'ofb', ''); $md5_key = md5 ($entry [T_CRYPT_KEY]); $iv = jirafeau_crypt_create_iv ($md5Key, mcrypt_enc_get_iv_size ($m)); mcrypt_generic_init ($m, $md5Key, $iv); $r = fopen (VAR_FILES . $p . $entry [T_HASH], 'r'); $content = ""; while (!feof ($r)) { $dec = mdecrypt_generic ($m, fread ($r, 1024)); $content .= $dec; ob_flush (); } fclose ($r); $zip->addFromString ($subdir."/".$entry [T_FILENAME], $content); mcrypt_generic_deinit ($m); mcrypt_module_close ($m); continue; } $zip->addFile (VAR_FILES.$p.$entry [T_HASH], $subdir."/".$entry [T_FILENAME]); } } $zip->close (); if (false) { // log $message .= print_r ($archiveInfo, 1); $message .= print_r ($archiveContent, 1); header ('HTTP/1.0 200 OK'); header ('Content-Length: ' . strlen ($message)); header ('Content-Type: text/plain'); echo $message; exit; } if (!is_file ($tmpFileName.T_ZIP_EXT,)) returnError (E_OPEN_ZIP); header ("Content-Type: application/zip"); header ('Content-Disposition: filename="'.$dirname.'.zip"'); $r = fopen ($tmpFileName.".zip", 'r'); while (!feof ($r)) { print fread ($r, 1024); ob_flush (); } fclose ($r); unlink ($tmpFileName.".zip"); unlink ($tmpFileName); exit; } // ======================================== // form $token = ''; if (isset ($_REQUEST [A_TOKEN]) && !empty ($_REQUEST [A_TOKEN])) { if (!preg_match ("/^([0-9a-zA-Z_-]+)$/", $_REQUEST [A_TOKEN])) return false; $token = $_REQUEST [A_TOKEN]; } $refToken = getToken ($sender); $urlBase = $_SERVER ['HTTP_X_FORWARDED_PROTO']."://".$_SERVER ['HTTP_HOST']; if (isset ($_REQUEST [A_ACTION]) && $_REQUEST [A_ACTION] == T_LOGIN && $sender) { require (JIRAFEAU_ROOT . 'lib/template/header.php'); if (getSenderFake ($sender)) echo "Ce compte ne peut plus se connecter. Veuillez contacter les administrateurs."; else { $token = setToken ($sender); // XXX test token $url = $urlBase.$_SERVER ['SCRIPT_NAME']."?".A_SENDER."=".$sender."&".A_TOKEN."=".$token; $result = sendEMail ($sender, "", M_EMAIL_SUBJECT, str_replace (["___LINK___", "___IP___", "___DATE___"], [$url, $_SERVER ['HTTP_X_REAL_IP'] , date ("Y-m-d H:i:s")], M_EMAIL_CONTENT)); if ($result) echo M_SEND_TOKEN; else echo "Erreur dans l'envoi. Véritiez votre mèl."; } echo "".M_BAD_SENDER_NAME."
"; else if (($token && !$refToken) || !getLoggedToken ($sender)) echo "".M_TOO_LONG_BEFORE_LOGGED."
"; else if ($token && $token != $refToken) echo "".M_BAD_TOKEN."
"; else if (getCreateToken ($sender) < strtotime (TOKEN_LOGOUT_LIMIT)) echo "".M_TOO_LONG_LOGGED."
"; ?> ".print_r ($link, 1)." mt: ".getTimeFile ($link ['hash']).""; if (!count ($link)) return; if (isKazArchive ($link)) { $dirName = $linkName; $dirLink = $link; $dirTime = $dirLink ['upload_date']; $archiveInfo = readArchiveFromLink ($dirLink); if (! count ($archiveInfo)) return; if ($sender != $archiveInfo [T_SENDER]) { setSenderFake ("rmdir: not owner", $sender, $archiveInfo [T_SENDER], $dirLink, null); $message .= "Tentative de supprimer un envoi dont vous n'êtes pas le propriétaire"; return; } $fileToDelete = false; if ($archiveInfo [T_NEW]) foreach ($archiveInfo [T_NEW] as [$fileName, $cryptKey]) { $fileLink = jirafeau_get_link ($fileName); if (! count ($fileLink)) continue; $fileTime = $fileLink ['upload_date']; if (! valideTime ($dirTime, $fileTime)) { setSenderFake ("rmdir: newfile not same time", $sender, null, $dirLink, $fileLink); $message .= "Cet envoi a été forgée". str_replace (["___FILENAME___", "___DIRTIME___", "___FILETIME___"], [$fileLink ['file_name'], $dirTime , $fileTime], M_INCONSISTENT_DATES); return; } $fileToDelete = true; } $message .= "l'envoi ".$archiveInfo [T_TIME]." est supprimé"; if ($fileToDelete) $message .= " avecInfo : ".$message."
"; echo M_LOGOUT; require (JIRAFEAU_ROOT.'lib/template/footer.php'); exit; } if (isset ($_REQUEST [A_ACTION])) { // change track switch (true) { case preg_match ("/^".A_RECORD."(on|off)$/i", $_REQUEST [A_ACTION], $matches): if ($matches [1] == "on") setSenderTrack ($sender); else rmSenderTrack ($sender); $message .= "Votre suivi à été mise à jour."; break; case preg_match ("/^".A_PERIOD."(".implode ("|", array_keys ($periodText)).")$/i", $_REQUEST [A_ACTION], $matches): setSenderPeriod ($sender, $matches [1]); $message .= "Votre période à été mise à jour."; break; } } // list $archives = []; $stack = array (VAR_LINKS); while ( ($d = array_shift ($stack)) && $d != null) { $dir = scandir ($d); foreach ($dir as $dirName) { if (strcmp ($dirName, '.') == 0 || strcmp ($dirName, '..') == 0 || preg_match ('/\.tmp/i', "$dirName")) { continue; } if (is_dir ($d . $dirName)) { /* Push new found directory. */ $stack [] = $d . $dirName . '/'; continue; } /* Read link informations. */ $l = jirafeau_get_link ($dirName); if (!count ($l)) continue; if (!isKazArchive ($l)) continue; $archiveInfo = readArchiveFromLink ($l); if ($sender != $archiveInfo [T_SENDER]) continue; $archiveInfo ['link'] = $dirName; $archiveInfo ['key'] = $l ['key']; $archiveInfo ['maxtime'] = $l ['time']; $archiveInfo ['hash'] = $l ['hash']; $archives [] = $archiveInfo; } } require (JIRAFEAU_ROOT . 'lib/template/header.php'); echo str_replace (["___SENDER___", "___DATE___"], [$sender, jirafeau_get_datetimefield (time ())], M_WELCOME); if ($message) echo "Info : ".$message."
"; echo ' '. 'Je veux que Kaz suive tous mes futurs envois: '. ''. ''; foreach ($trackText as $item => $text) echo ''.$text.' '; echo ''. ''. ''. ''; $userSise = 0; $userTab = []; if ($archives) { foreach ($archives as $archiveInfo) { $contentSize = 0; $archContent = ''; foreach ([T_NEW, T_OLD] as $cat) { $liStyle = $cat == T_NEW ? "font-weight: bold;" : "font-style: italic;"; if (isset ($archiveInfo [$cat])) foreach ($archiveInfo [$cat] as [$linkName, $cryptKey]) { $link = jirafeau_get_link ($linkName); if (count ($link) == 0) continue; if ($cat == T_NEW ) $contentSize += $link ['file_size']; $lf = $linkName; $kf = $link ['key']; $archContent .= 'Votre compte occupe '.jirafeau_human_size ($userSise).'.
'. ''; if (count ($userTab)) { foreach ($userTab as $time => $entry) echo $entry; } else echo "Il n'y a aucune information vous concernant.
"; require (JIRAFEAU_ROOT.'lib/template/footer.php'); exit; // ========================================