PK 95J Temp.PM - Source Code (v3.8.1)/PK
Q)H}& D Temp.PM - Source Code (v3.8.1)/1tempAitLUWwgNGhiJjAxXegv61tXd6x2.pngPNG
IHDR #3 mIDATxAn Dঐ4`4MU^|x<|߆|ې:6jR-ăFB,ciz[D*"XH9T>;|ڦA$*A}'\lV"*yN A->Sfl˰R>䊷RHb)&o^ 'םnVp'$ou%nhM7R탅b"ڏHFIĸm֩@hh6dS+^v (l9
Whl)AOrIɽlkpX(\'{_J t;rk_3H^N>$!'B9CyA>W/vph IENDB`PK
5JƱ 1 Temp.PM - Source Code (v3.8.1)/README_INSTALL.txtTemp.PM - Temporary Private Message
-----------------------------------------
Contact: temp.pm (at) riseup (dot) net / temp.pm (at) protonmail (dot) com
Web: https://temp.pm
License: Do what you want but keep it free and open source and include original authors info/contact details!
Requirements:
- HTTP server with HTTPS/SSL (preferably Apache2, with mod_rewrite + mod_headers)
- PHP - Tested with PHP 7.0, should work with PHP5+
- php-mcrypt, php-cli, php-sqlite3
- mcrypt
- crontab
- shred (coreutils)
-----------------------------------------
Install:
1. Edit these files to suit your needs. Most important settings are at the top of the files:
index.php
load.php
delete_expired.php
update_stats.php
csrf_table_update.php
htaccess_example.txt (rename this to .htaccess)
IMPORTANT! Message and stats directories should NOT BE accessible from outside the server! (ie. NOT in /var/www/html/)
Apache site configuration example is in apache_example.txt
2. Copy all necessary content to your www document dir
3. Create these message/stats directories (change the paths accordingly to the ones you used earlier, for example):
/path/for/messages/txt
/path/for/messages/txt/stats
/path/for/messages/txt/1
/path/for/messages/txt/12h
/path/for/messages/txt/15m
/path/for/messages/txt/1h
/path/for/messages/txt/3
/path/for/messages/txt/30
/path/for/messages/txt/30m
/path/for/messages/txt/45m
/path/for/messages/txt/60
/path/for/messages/txt/6h
/path/for/messages/txt/7
/path/for/messages/txt/stats
/path/for/messages/txt/stats/1
/path/for/messages/txt/stats/30
/path/for/messages/txt/stats/7
/path/for/messages/txt/stats/random
4. Create these files (edit the paths accordingly to the ones you used earlier, for example):
/path/for/messages/txt/stats/1.txt
/path/for/messages/txt/stats/30.txt
/path/for/messages/txt/stats/7.txt
/path/for/messages/txt/stats/hits.txt
/path/for/messages/txt/stats/waiting.txt
5. Add these entries to root user's crontab (edit the paths accordingly to the ones you used earlier, for example):
@reboot swapoff -a >/dev/null 2>&1 ;
* * * * * php /path/for/www/delete_expired.php >/dev/null 2>&1 ;
*/15 * * * * php /path/for/www/update_stats.php >/dev/null 2>&1 ;
*/15 * * * * php /path/for/www/csrf_table_update.php >/dev/null 2>&1 ;
6. Make sure that everything works (create a message and try to read it twice)
7. Please disable all HTTP server/Apache logs (just comment them out in your configs), disable swapping (from fstab) and don’t keep backups of the message data! It’s also recommended to store the message data inside a VeraCrypt partition/container for added security. An official SSL certificate is also very highly recommended!
8. IF YOU USE THIS SCRIPT PUBLICLY/ONLINE, PLEASE KEEP IT UPDATED!
Latest source code package can be found at https://temp.pm/?about
Send us an email (address is at the top of this document) if you wish to be notified when a new version is released.
Regards,
Temp.PM staff
PK
95J.{ { 0 Temp.PM - Source Code (v3.8.1)/announcements.phpTitle – Message.';
//$announcement_msg[1] = 'Title – Message.';
//$announcement_msg[2] = 'Title – Message.';
// Use this to add some vertical spacing if you use multiple lines:
//
?>PK
iG 1 Temp.PM - Source Code (v3.8.1)/apache_example.txt# Replace your-domain-here.com with your own domain!
# Hide operating system and Apache version
ServerSignature Off
ServerTokens Prod
ServerAdmin noreply@your-domain-here.com
ServerName your-domain-here.com
ServerAlias www.your-domain-here.com
UseCanonicalName on
Redirect 301 / https://your-domain-here.com/
ServerAdmin noreply@your-domain-here.com
ServerName your-domain-here.com
ServerAlias www.your-domain-here.com
UseCanonicalName on
DocumentRoot /var/www
AllowOverride All
Options -Indexes
# Enable SSL
SSLEngine on
# SSL configs
SSLProtocol ALL -SSLv2 -SSLv3
SSLCompression off
SSLHonorCipherOrder on
SSLCipherSuite "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:TLS_FALLBACK_SCSV:!aNULL:!MD5:!DSS"
SSLOptions +StrictRequire
# SSL certs
SSLCertificateFile /etc/ssl/your-domain-here.com.crt
SSLCertificateKeyFile /etc/ssl/your-domain-here.comkey
SSLCACertificateFile /etc/ssl/your-domain-here.com.ca-bundle
# SSL tweaks
SSLOptions +StdEnvVars +StrictRequire
SSLOptions +StdEnvVars +StrictRequire
BrowserMatch "MSIE [2-6]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
PK
t.IĐ4O 3 Temp.PM - Source Code (v3.8.1)/csrf_table.sqlite.dbSQLite format 3 @ -
X ggXX iWW1tablesqlitebrowser_rename_column_new_tablesqlitebrowser_rename_column_new_tableCREATE TABLE `sqlitebrowser_rename_column_new_table` (
`csrf_id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`csrf_hash` TEXT,
`csrf_date` TEXT
) !!{tablecsrf_tablecsrf_tableCREATE TABLE "csrf_table" (
`csrf_id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`csrf_hash` TEXT,
`csrf_date` TEXT
)P++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq) s}W indexsqlite_autoindex_sqlitebrowser_rename_column_new_table_1sqlitebrowser_rename_column_new_table = 3
G! indexsqlite_autoindex_csrf_table_1csrf_table
(Wsqlitebrowser_rename_column_new_table
!csrf_table
PK
4J~A 4 Temp.PM - Source Code (v3.8.1)/csrf_table_update.php 'sqlite',
'database_file' => '/path/for/csrf_table.sqlite.db'
]);
//__________________________
// Get all rows
if ( $datas = $db_csrf->select("csrf_table", [
"csrf_id",
"csrf_hash",
"csrf_date"
], [
"csrf_id[>]" => 0
]) )
// Success: found some rows
{
echo '0';
}
// Error: no rows found
else {
echo '1';
}
// Process rows
foreach($datas as $data)
{
// Delete entries older than 24 hours (1440 seconds)
if ($data["csrf_date"] < time()-1440) {
$db_csrf->delete("csrf_table", [ "csrf_id" => $data["csrf_id"] ]);
}
}
?>PK
4J# 1 Temp.PM - Source Code (v3.8.1)/delete_expired.phpSecurely deleting expired messages... ';
echo ' ';
}
//___________________________________________________________
// Process all timers/directories
foreach ( $d as $dir => $time_check ) {
// List all files (messages) for specified directory
foreach (glob($messages_path.'/'.$dir.'/*') as $file){
// Check if message is expired
if ( filemtime($file) <= $time_check ){
// Increment counter
$count++;
// Securely delete file (7-pass shred)
exec("sudo shred -f --remove=unlink -n 7 $file");
// Print deleted file info when running via command line
if ( defined('STDIN') ) {
$file_print = str_replace($messages_path, '', $file);
echo $count.': Deleted: '.$file_print.PHP_EOL;
}
elseif ( $print_stats == '1' ) {
$file_print = str_replace($messages_path, '', $file);
echo ''.$count.': Deleted: '.$file_print.' ';
}
} // end of: check if message is expired
} // end of: foreach: list messages for specified directory
} // end of: foreach: process all timers/directories
//___________________________________________________________
// Stop execution timer
$time_end = microtime(true);
$time_total = $time_end - $time_start + 0;
$time_total = round($time_total, 4);
// Print total stats (when using php-cli)
if ( defined('STDIN') ) {
echo PHP_EOL;
echo 'Total messages deleted: '.$count.PHP_EOL;
echo 'Total execution time: '.$time_total.' sec'.PHP_EOL;
echo '______________________________________'.PHP_EOL;
echo PHP_EOL;
}
// Print total stats (when NOT using php-cli)
elseif ( $print_stats == '1' ) {
echo ' ';
echo 'Total messages deleted: '.$count.' ';
echo 'Total execution time: '.$time_total.' sec ';
echo ' ';
}
elseif ( $print_stats == '0' ){
echo 'All done!';
}
?>
PK
4Jo ( Temp.PM - Source Code (v3.8.1)/error.phpPossible causes:
● Directory listing is disabled
● Incorrect login
';
}
// 403
elseif($error_code == '403'){
$error_msg_short = 'Forbidden';
$error_msg_long = '
Possible causes:
● We are performing a quick maintenance, try again soon!
● Insufficient file permissions
● Directory listing has been disabled
';
}
// 404
elseif($error_code == '404'){
$error_msg_short = 'File Not Found';
$error_msg_long = '
Possible causes:
● The file has been deleted or moved
● There is a typo in the URL
';
}
// 410
elseif($error_code == '410'){
$error_msg_short = 'Resource Gone';
$error_msg_long = 'There was a page here, but forwarding address is missing. ';
}
// 500
elseif($error_code == '500'){
$error_msg_short = 'Internal Server Error';
$error_msg_long = '
Possible causes:
● Invalid .htaccess configuration
● Server overload
● A script stops with an error
';
}
// 503
elseif($error_code == '503'){
$error_msg_short = 'Service Unavailable';
$error_msg_long = '
Possible causes:
● Server overload
● Connection refused
';
}
// 505
elseif($error_code == '505'){
$error_msg_short = 'HTTP Version Not Supported';
$error_msg_long = 'The requested HTTP protocol version is not supported.';
}
//
else{
$error_code = '';
$error_msg_short = 'Something went wrong!';
$error_msg_long = '';
}
//-----------------
//=====================================================================================================
?>
Error -
Error -
';
echo '
';
echo $error_msg_long;
echo '
';
}
?>
PK
bFsb~ ~ * Temp.PM - Source Code (v3.8.1)/favicon.ico h ( J s s s s s s s s s s s J n n n n n n n n n n n n n n n n n n n n zzzzzzzzzzzzzzz Gzzzzzzzzzzzzzzzzzz G $zzzzzzzzzzzzzzzzzz $ zzzTzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzT PK
Q)HK~ ~ 0 Temp.PM - Source Code (v3.8.1)/favicon_error.ico h ( s ] ] PK
bFm - Temp.PM - Source Code (v3.8.1)/hiddenmode.txtHidden mode
When you need to read a message and you are in a place where someone else might be looking at what you are doing in your web browser, you may want to use the hidden mode.
In hidden mode the message content is hidden using black bars and you need to hover your mouse pointer over the bars to reveal the content.
This feature is CSS based so you don't need to have JavaScript enabled.
With a mobile device, you may need to select and copy the black bars to a text editor app instead. In some text editors, you may also need to change the text colour or text background colour.
Please note that in order to use the hidden mode, the message must be unread, meaning that you can't switch from normal mode to hidden mode if you are already reading the message in normal mode.
To use hidden mode, simply copy the normal message URL, change the last letter to H and open it in your browser.
Example:
https://temp.pm/?xxxxxx-x-xxxxxx-N = Normal mode
https://temp.pm/?xxxxxx-x-xxxxxx-H = Hidden modePK
2JWE E 3 Temp.PM - Source Code (v3.8.1)/htaccess_example.txt# Replace your-domain-here.com with your own domain name!
# Force SSL
SSLOptions +StrictRequire
SSLRequireSSL
# Enable Strict-Transport-Security, anti-clickjacking etc.
FileETag None
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate, pre-check=0, post-check=0"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set X-WebKit-CSP "frame-ancestors 'self';"
Header set X-Content-Security-Policy "frame-ancestors 'self';"
Header set Content-Security-Policy "frame-ancestors 'self';"
Header set Referrer-Policy "no-referrer"
# Forward non-www (normal)
RewriteCond %{SERVER_PORT} 80
RewriteCond %{HTTP_HOST} ^www\.your-domain-here\.com [NC]
RewriteRule (.*) http://your-domain-here.com/$1 [R=301,L]
# Forward non-www (HTTPS)
RewriteCond %{SERVER_PORT} 443
RewriteCond %{HTTP_HOST} ^www\.your-domain-here\.com [NC]
RewriteRule (.*) https://your-domain-here.com/$1 [R=301,L]
# Error pages
# Error pages
ErrorDocument 400 /error.php
ErrorDocument 401 /error.php
ErrorDocument 403 /error.php
ErrorDocument 404 /error.php
ErrorDocument 405 /error.php
ErrorDocument 408 /error.php
ErrorDocument 410 /error.php
ErrorDocument 411 /error.php
ErrorDocument 412 /error.php
ErrorDocument 413 /error.php
ErrorDocument 414 /error.php
ErrorDocument 415 /error.php
ErrorDocument 500 /error.php
ErrorDocument 501 /error.php
ErrorDocument 502 /error.php
ErrorDocument 503 /error.php
ErrorDocument 505 /error.php
ErrorDocument 506 /error.php
# ErrorDocument fix for 403
Allow from all
Satisfy any
PK
5JXH ( Temp.PM - Source Code (v3.8.1)/index.php
window.onload=WindowLoad;
function WindowLoad(event) {
jsCountDown("jsCountDown", "3600");
}
var _countDowncontainer=0;
var _currentSeconds=0;
function jsCountDown(strContainerID, initialValue) {
_countDowncontainer = document.getElementById(strContainerID);
if (!_countDowncontainer) {
return;
}
SetCountdownText(initialValue);
window.setTimeout("CountDownTick()", 1000);
}
function CountDownTick() {
if (_currentSeconds <= 0) {
return;
}
SetCountdownText(_currentSeconds-1);
window.setTimeout("CountDownTick()", 1000);
}
function SetCountdownText(seconds) {
_currentSeconds = seconds;
var minutes=parseInt(seconds/60);
seconds = (seconds%60);
var hours=parseInt(minutes/60);
minutes = (minutes%60);
var strText = AddZero(hours) + ":" + AddZero(minutes) + ":" + AddZero(seconds);
_countDowncontainer.innerHTML = strText;
}
function AddZero(num) {
return ((num >= 0)&&(num < 10))?"0"+num:num+"";
}
';
*/
//_________________________________________________________
// Random string generation for page hits and form resubmit prevention
$hit_file = generateRandom("64");
// Create a new file for every page hit
touch(STATS_PATH_ABSOLUTE."/hits/$hit_file");
//============================================================================================
// Function: Generate random string with specified length (Uses numbers and uppercase and lowercase alphabets)
function generateRandom($length) {
$generated = '';
for ($i=0;$i<=$length;$i++) {
$chr = '';
switch (mt_rand(1,3)) {
case 1:
$chr = chr(mt_rand(48,57));
break;
case 2:
$chr = chr(mt_rand(65,90));
break;
case 3:
$chr = chr(mt_rand(97,122));
}
$generated.=$chr;
}
return $generated;
}
//_____________
// Function: Save CSRF data to database (1 = success)
function saveCSRF($hash) {
// Database for hits today
$db_csrf = new Medoo([
'database_type' => 'sqlite',
'database_file' => '/path/for/csrf_table.sqlite.db'
]);
if ( $db_csrf->insert("csrf_table", [
"csrf_hash" => $hash,
"csrf_date" => time()
]) ){
return 1;
}
else {
return 0;
}
}
//_____________
// Function: check if CSRF data is found in the database (1 = success)
function checkCSRF($hash) {
// Database for hits today
$db_csrf = new Medoo([
'database_type' => 'sqlite',
'database_file' => '/path/for/csrf_table.sqlite.db'
]);
if ( $db_csrf->has("csrf_table", [
"csrf_hash" => $hash
]) ){
return 1;
}
else {
return 0;
}
}
// Function: delete CSRF data from the database (1 = success)
function deleteCSRF($hash) {
// Database for hits today
$db_csrf = new Medoo([
'database_type' => 'sqlite',
'database_file' => '/path/for/csrf_table.sqlite.db'
]);
if ( $db_csrf->delete("csrf_table", [
"csrf_hash" => $hash
]) ){
return 1;
}
else {
return 0;
}
}
//_____________
// Function: Generate salt (or IV) using mcrypt. Default length is 128 bits (16 bytes)
function generateSalt($bytes = '16'){
return mcrypt_create_iv($bytes, MCRYPT_RAND);
}
//_____________
// Function: Decrypt message (AES-256-CBC, output: base64, IV: 128 bits)
function encryptData($openssl_data, $openssl_pass, $openssl_iv){
$method = 'AES-256-CBC';
if(strlen($openssl_iv) > '128'){
$openssl_iv = substr($openssl_iv, 0, 128);
}
return trim(openssl_encrypt($openssl_data, $method, $openssl_pass, FALSE, $openssl_iv));
}
//_____________
// Function: Encrypt message (AES-256-CBC, output: base64, IV: 128 bits)
function decryptData($openssl_data, $openssl_pass, $openssl_iv){
$method = 'AES-256-CBC';
if(strlen($openssl_iv) > '128'){
$openssl_iv = substr($openssl_iv, 0, 128);
}
return trim(openssl_decrypt($openssl_data, $method, $openssl_pass, FALSE, $openssl_iv));
}
//_____________
// TODO this code is not in use:
// Function: Convert URLs to links to the external website warning page
// TODO fix relative_path_to_script (isn't passed in the function "header")
/*
function convertURLs($s) {
return preg_replace('@(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@', '$1', $s);
}
*/
//_____________
// Function: Ping server / check online status
function pingServer($host, $port, $timeout){
$starttime = microtime(true);
$file = fsockopen ($host, $port, $errno, $errstr, $timeout);
$stoptime = microtime(true);
$status = 0;
// Server is down
if(!$file){
$status = -1;
}
// Otherwise print response time in milliseconds
else{
fclose($file);
$status = ($stoptime - $starttime) * 1000;
$status = floor($status);
}
return $status;
}
//_____________
// Function: Server uptime
function getServerUptime(){
//if(PHP_OS == "Linux") {
$uptime = @file_get_contents("/proc/uptime");
//if ($uptime !== false) {
$uptime = explode(" ",$uptime);
$uptime = $uptime[0];
$days = explode(".",(($uptime % 31556926) / 86400));
$hours = explode(".",((($uptime % 31556926) % 86400) / 3600));
$minutes = explode(".",(((($uptime % 31556926) % 86400) % 3600) / 60));
$time = '';
// Days
if($days[0] == '0'){
$time = '';
}
elseif($days[0] == '1'){
$time = "$days[0] day";
}
elseif($days[0] > '1'){
$time = "$days[0] days";
}
// Hours
if($hours[0] == '0'){
$time = $time;
}
elseif($hours[0] == '1'){
$time = $time.", $hours[0] hour";
}
elseif($hours[0] > '1'){
$time = $time.", $hours[0] hours";
}
// Minutes
if($minutes[0] == '0'){
$time = $time;
}
elseif($minutes[0] == '1'){
$time = $time.", $minutes[0] min";
}
elseif($minutes[0] > '1'){
$time = $time.", $minutes[0] mins";
}
// Fix leading commas (when uptime is less than 1 day)
if(substr($time, 0, 2) == ', '){
$time = substr($time, 2, (strlen($time)-2));
}
return $time;
}
//_____________
// Function: System load average
function getSystemLoad(){
$load_source = substr(strrchr(shell_exec("uptime"),":"),1);
$load = array_map("trim",explode(",",$load_source));
$load = $load[0].', '.$load[1].', '.$load[2];
return $load;
}
//_____________
// Function: CPU usage percentage
function getCPUusage(){
exec('ps -aux', $processes);
foreach($processes as $process){
$cols = split(' ', ereg_replace(' +', ' ', $process));
if(strpos($cols[2], '.') > -1){
$cpu_usage += floatval($cols[2]);
$cpu_usage = round($cpu_usage, 0);
}
}
// Fix if over 100% (TODO not sure why it does this?)
if ($cpu_usage > '100') {
$cpu_usage = '100';
}
return $cpu_usage.'%';
}
//_____________
// Function: memory usage percentage
function getMemUsage(){
// Resets
$total = 0;
$free = 0;
$cached = 0;
// Open file handle
$fh = fopen('/proc/meminfo','r');
// Loop
while($line = fgets($fh)) {
$pieces = array();
// Total memory
if(preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces)){
$total = $pieces[1];
}
// Free memory
if(preg_match('/^MemFree:\s+(\d+)\skB$/', $line, $pieces)){
$free = $pieces[1];
}
// Cached memory
if(preg_match('/^Cached:\s+(\d+)\skB$/', $line, $pieces)){
$cached = $pieces[1];
}
// Break loop when both are set
if(!empty($total) && !empty($free) && !empty($cached)){
break;
}
}
// Close file handle (/proc/meminfo)
fclose($fh);
// Convert all values from kB to GB and round to 2 decimal places
$total = ($total / 1024 / 1024);
$total = round($total, 2);
$free = ($free / 1024 / 1024);
$free = round($free, 2);
$cached = ($cached / 1024 / 1024);
$cached = round($cached, 2);
// Fix if there is something weird with memory usage (TODO not sure why it does this?)
if($cached > $free){
$usage_percentage = round(((($total - $cached)/$total)*100), 0);
}
elseif($cached < $free){
$usage_percentage = round(((($total - $free)/$total)*100), 0);
}
// Fix if over 100% (TODO not sure why it does this?)
if ($usage_percentage > '100') {
$usage_percentage = '100';
}
return $usage_percentage.'%';
}
// Generate random CSRF data + hash it with MD5
$csrf_generated = hash('md5', generateRandom("64"));
// HTTP header for page refresh (wipe) after 1 hour when reading a message or after creating a message
if (!empty($id) && !empty($d) && !empty($p) || $query == "create" || isset($_POST['create'])) {
header('Refresh: 3600; URL=https://'.SERVER_DOMAIN_NORMAL.'/');
}
// HTTP header for main page refresh (wipe) after 23 hours
elseif ($query == "") {
header('Refresh: 82800; URL=https://'.SERVER_DOMAIN_NORMAL.'/');
}
//============================================================================================
?>
';
}
// Refresh (wipe) the main page after 23 hours
elseif ($query == "") {
echo '
';
// No refresh for other/normal pages
}
else {
echo ' ';
}
?>
Temp.PM - Temporary Private Message
) only on the main page
if ( $query == "" ) {
echo '';
}
else {
echo '';
}
?>
';
} // end: if (announcement has content)
} // end: for loop
} // end: if (announcement is not empty)
//============================================================================================
// Hidden mode info page
if($query == "hiddenmode" && file_exists('hiddenmode.txt')){
// Get hidden mode info from file
$hiddenmode_content = trim(file_get_contents('hiddenmode.txt', FILE_USE_INCLUDE_PATH));
// Convert spaces to
$hiddenmode_content = nl2br($hiddenmode_content);
// Print contents
if(!empty($hiddenmode_content)){
// Print the news
echo '
Canary A warrant canary is a colloquial term for a regularly published statement that a service provider has not received legal process that it would be prohibited from saying it had received.
The statement can be found below or you can use the plain text version. Verify the signature with our PGP key.
';
// Get content from file
$canary_content = file_get_contents('canary.txt', FILE_USE_INCLUDE_PATH);
// Check if content exists
if (!empty($canary_content)) {
// Trim and convert spaces to
$canary_content = trim(nl2br($canary_content));
// Print content
echo $canary_content;
}
// Otherwise print error message
else {
echo '
Error!
Page content not found! Sorry for the inconvenience. Please try again later.
';
}
//============================================================================================
/*
// External links
elseif(substr($query, 0, 4) == 'link' && !empty($link)){
// Print the information about the external link
echo '
Link to external website
• The purpose of this page is to inform you about the dangers of external websites.
• Be aware that the external website may compromise your privacy/security or be harmful to your computer.
• To hide your browser\'s referer information, copy the URL below and paste it to your address bar.
• If you just wish to proceed normally, click on the link below.
';
// // Encode some characters to HTML equivalens (prevents using HTML in messages)
$link = htmlentities($link, ENT_QUOTES | ENT_HTML401);
// Print the link
echo '
';
// If URL is valid -> print link with href
if(filter_var($link, FILTER_VALIDATE_URL)){
echo ''.$link.'';
}
// Otherwise (URL is invalid) -> print link without href
else {
echo $link;
}
echo '
';
}
*/
//============================================================================================
// About page
elseif($query == "about"){
// Get the message counts
$count = file_get_contents(STATS_PATH_ABSOLUTE."/waiting.txt");
$new_messages_1d = file_get_contents(STATS_PATH_ABSOLUTE."/1.txt");
$new_messages_7d = file_get_contents(STATS_PATH_ABSOLUTE."/7.txt");
$new_messages_30d = file_get_contents(STATS_PATH_ABSOLUTE."/30.txt");
$page_hits_1d = file_get_contents(STATS_PATH_ABSOLUTE."/hits.txt");
// OLD:
// It uses strong encryption, secure deletion and the message URLs are protected against bruteforce attacks. You can also use your own custom password for additional protection.
// Print about page content
echo '
About
Temp.PM (formely known as ParaNote) stands for Temporary Private Message. You can create messages which will self-destruct after being read or after a timer expires if they won\'t be read in time. We have a strong emphasis on security and privacy.
Only those who have the complete message URL can decrypt/read the message which means that we can\'t give decrypted messages to third-parties or even to our own admins, even if we wanted to!
Compared to many other similar services and projects - Temp.PM is actively developed, it has many security features that others don\'t have and it\'s compatible with almost every web browser and device.
Features
• Double encrypted with 256-bit AES (message content + file system)
• Secure deletion with 7-pass shred
• Forced HTTPS/TLS connection
• Self-destruction timer
• Bruteforce protection
• Optional custom password protection
• Dedicated server located in Europe
• Free & open source
• No swap, no cache, no logs, no tracking, no backups, no ads!
';
// Print message stats and page hits (if stats path is found)
if(file_exists(STATS_PATH_ABSOLUTE)){
echo '
';
// Spacing to make both stats divs as tall
//echo '
';
// End of message stats table
echo '
';
}
// Contact
echo '
Contact admins
';
// TODO not in use anymore (was a good script though, the noscript option doesn't work with html code though sadly (was using img src with image of the email address)
/*
*/
// Print contact email with HTML entities (converted via https://mothereff.in/html-entities)
echo '
temp.pm (at) riseup (dot) net
temp.pm (at) protonmail (dot) com
';
// Print PGP key link
echo '
Donations
Temp.PM is 100% free to use but of course it costs us money to run it, so donations of any size are appreciated.
BitCoins can be sent to the address that is shown in the page footer. QR code can be found here.
';
// Print version & source code stuff //(if the files exist)
if(file_exists('Temp.PM-source_code.zip')){
echo '
Version & source code
Site is currently running on v'.VERSION.'.
Git repository will be set up some day. In the mean time, the source code can be downloaded here but it may not always be the most recent version, email us to make sure.
';
//============================================================================================
}
// Error: File system is NOT mounted OR message reading is disabled from settings OR when mcrypt/openssl/shred/rm is NOT installed/working
elseif(!file_exists(MESSAGE_PATH_ABSOLUTE) || !function_exists('exec') || !exec("shred --help") || !exec("rm --help") || !function_exists('openssl_encrypt') || !function_exists('openssl_decrypt') || !function_exists('mcrypt_create_iv') || !function_exists('Proc_Open') || !function_exists('Proc_Close')){
echo '
Error!
File system is not mounted or required functions are not accessible. If this error persists, please contact the admins.
';
//============================================================================================
}
// Error: Message not found or it has already been read
elseif(!empty($d) && !empty($id) && !empty($p) && !file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".counter")){
echo '
';
}
*/
//============================================================================================
// Read message (both types)
elseif(!empty($d) && !empty($id) && !empty($p) > "" && file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".counter") && MESSAGE_READING_ENABLED == "1"){
// Get the bruteforce counter value
$message_counter_file = MESSAGE_PATH_ABSOLUTE."/"."$d"."/"."$id".".counter";
$hits = file_get_contents($message_counter_file);
// Delete message and bruteforce counter file if bruteforce threshold is exceeded (if not using custom password)
if(!file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".pass")){
if($hits >= BRUTEFORCE_THRESHOLD){
// Run deletions in background process
Proc_Close (Proc_Open (MESSAGE_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." $message_counter_file &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id".".iv &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id".".debug"." &", Array (), $foo)); // TODO debug
}
// Otherwise increment the bruteforce counter
else{
$hits++;
file_put_contents($message_counter_file, $hits, LOCK_EX);
}
}
// Get message file contents (encrypted data)
$read_note = file_get_contents(MESSAGE_PATH_ABSOLUTE."/$d/$id");
// Get IV from file (for decryption) and base64 decode it
if(file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".iv")){
$iv = base64_decode(file_get_contents(MESSAGE_PATH_ABSOLUTE."/$d/$id".".iv"));
}
// Decrypt message content
if(file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".pass") && !empty($cpass_read)){
// Decrypt message
$decrypted_note = decryptData($read_note, "$p"."$cpass_read", $iv);
// Wipe variables
$read_note = '';
$iv = '';
// Get the decryption check part of the note
$decrypt_check_string = "$p"."$cpass_read";
$decrypted_note_end_for_checking = substr($decrypted_note, (strlen($decrypt_check_string) * -1));
}
elseif(!file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".pass")){
// Decrypt message
$decrypted_note = decryptData($read_note, $p, $iv);
// Wipe variables
$read_note = '';
$iv = '';
// Get the decryption check part of the note
$decrypt_check_string = $p;
$decrypted_note_end_for_checking = substr($decrypted_note, (strlen($decrypt_check_string) * -1));
}
// If decryption is successful -> print message TODO poista 2015
if($decrypted_note_end_for_checking == $decrypt_check_string && !empty($decrypted_note_end_for_checking) && !empty($decrypt_check_string)){
// Run deletions in background process
Proc_Close (Proc_Open (MESSAGE_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." $message_counter_file &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id".".pass"." &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id".".iv"." &", Array (), $foo));
Proc_Close (Proc_Open (NORMAL_DELETE_PARAMETERS." ".MESSAGE_PATH_ABSOLUTE."/$d/$id".".debug"." &", Array (), $foo)); // TODO debug
// Strip the decryption check code from the note
$decrypted_note = substr($decrypted_note, 0, (strlen($decrypt_check_string) * -1));
/*
// Redirect to error page (use sessions: redirect_to_page = error_read_general) TODO
else{
}
*/
// Print countdown timer (JavaScript)
echo $js_timer;
//_______________________
// Kill mode: delete message (don't show it, just print info message)
if ($mode_query == 'K' || $mode_query == 'D') {
// Wipe the message variable
$decrypted_message = '';
// Print delete successful message
echo '
Message deleted successfully!
• It has now been securely deleted, as you requested.
';
} else {
//_______________________
echo '
Attention!
• This message has now been securely deleted. You can\'t open the URL again or refresh this page!
• If you need to save the message contents somewhere, please make sure you use appropriate encryption.
';
// Get the wipe time/date for non-JS users (TODO somehow this requires 3 hours instead of 1 ??? time zone thing???)
/*
$wipe_date = time() + (60 * 60 * 4);
$wipe_date = DateTime::createFromFormat('U', $wipe_date);
//$wipe_date = $wipe_date->format('j.n.Y - H:i');
$wipe_date = $wipe_date->format('H:i A');
*/
echo '• The contents of this page will disappear in 1 hour.';
//echo 'Based on server time it will happen at '.$wipe_date;
/*
// Print the countdown timer (no JavaScript)
echo '
';
// Print the countdown timer (JavaScript)
echo "
";
*/
echo '
';
/*
// Convert URLs to links to the external website warning page only when hidden mode is not being used
if($mode_query != "HH"){
$decrypted_note = convertURLs($decrypted_note); // TODO fix when using links like: "https://temp.pm/ "
}
*/
// If hidden mode is enabled -> convert the message
if($mode_query == "HH"){
// Doesn't work with http:// content TODO
//$decrypted_note = preg_replace('([a-zA-Z.,!?0-9]+(?![^<]*>))', '$0', $decrypted_note);
// Fix line breaks (part 1/2)
$decrypted_note = str_replace(' ', ' ', $decrypted_note);
// Replace spaces and line breaks with spans
$decrypted_note = str_replace(' ', ' ', $decrypted_note);
$decrypted_note = str_replace(' ', ' ', $decrypted_note);
// Add spans to both ends of the string
$decrypted_note = ''.$decrypted_note.'';
// Fix line breaks (part 2/2)
$decrypted_note = str_replace(' ', ' ', $decrypted_note);
// Print hidden mode info
echo '
Hidden mode is enabled!
• Hover your mouse pointer over the black bars to reveal the content.
• When using a mobile device, you may need to select and copy the black bars to a text editor app instead.
• In some text editors, you may also need to change the text colour or text background colour.
';
}
// Print the decrypted message content
echo '
'.$decrypted_note.'
';
// Wipe the decrypted message variable
$decrypted_note = '';
// TODO include debugger if it's enabled
if (file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".debug")) {
include('debug_debug.php');
}
} // end: kill mode (and hidden mode + normal mode as well)
/*
// Reset variable to allow random generation below
$stat_file_exists = '1';
// Generate random filename for stats and make sure it doesn't exist
while($stat_file_exists == "1"){
// Generate random 64bit string
$stats_file = generateRandom("64");
// Filename already exists -> new one will be generated
if(file_exists(STATS_PATH_ABSOLUTE."/read/30/$stats_file") || strlen($stats_file) < "64"){
$stat_file_exists = "1";
}
else{
// Stat file name is unique
$stat_file_exists = "0";
// Create stats files
touch(STATS_PATH_ABSOLUTE."/read/1/$stats_file");
touch(STATS_PATH_ABSOLUTE."/read/7/$stats_file");
touch(STATS_PATH_ABSOLUTE."/read/30/$stats_file");
} // end of else (filename already exists -> new one will be generated)
} // end of while stat_file_exists == 1
*/
// Print footer
echo '
';
//============================================================================================
}
*/
// Create a new message
elseif(isset($_POST['create']) && !empty($note) && !empty($csrf_post) && MESSAGE_CREATION_ENABLED == '1' && checkCSRF($csrf_post) == '1'){
// Validate TTL value (defaults to 3 days)
if (preg_match('/[^A-Za-z0-9]/', $ttl) or empty($ttl)) {
$ttl = '3';
}
// Encode some characters to HTML equivalens (prevents using HTML in messages)
$note = htmlentities($note, ENT_QUOTES | ENT_HTML401);
// Convert line breaks
$note = nl2br($note);
// Randomize message ID and password lengths (if needed)
if($filename_min_length == $filename_max_length) {
$file_random_len = $filename_max_length;
}
else {
$file_random_len = mt_rand($filename_min_length, $filename_max_length);
}
if($pass_min_length == $pass_max_length) {
$pass_random_len = $pass_max_length;
}
else {
$pass_random_len = mt_rand($pass_min_length, $pass_max_length);
}
// Generate random password
$pass = generateRandom($pass_random_len);
// Generate IV (for encryption)
$iv = generateSalt(16);
// Add password inside the encrypted message (for decryption verification purposes) and encrypt content
//$note = "$note"."$decrypt_check_string"; // TODO poista 2015
$note = "$note"."$pass"."$cpass_create";
$message_encrypted = encryptData($note, "$pass"."$cpass_create", $iv);
// Wipe note variable (just in case)
$note = '';
// Base64 encode IV
$iv = base64_encode($iv);
// Generate random filename and make sure it doesn't exist
while($message_exists == '1'){
// Generate random filename
$file = generateRandom($file_random_len);
// Filename already exists -> new one will be generated
if(file_exists(MESSAGE_PATH_ABSOLUTE."/$ttl/$file") || file_exists(MESSAGE_PATH_ABSOLUTE."/$ttl/$file".".counter") || file_exists(MESSAGE_PATH_ABSOLUTE."/$ttl/$file".".pass") || file_exists(MESSAGE_PATH_ABSOLUTE."/$ttl/$file".".iv")){
$message_exists = '1';
}
else{
// Exit the while loop
$message_exists = '0';
// Message file path
$message_file = MESSAGE_PATH_ABSOLUTE."/$ttl/$file";
$message_counter_file = "$message_file".".counter";
// IV file path
$iv_file = "$message_file".".iv";
// Write message to file
file_put_contents($message_file, $message_encrypted, LOCK_EX);
// Write IV to file
file_put_contents($iv_file, $iv, LOCK_EX);
// Create empty bruteforce protection counter
file_put_contents($message_counter_file, '0', LOCK_EX);
// Create custom pass check file
if(!empty($cpass_create)){
touch(MESSAGE_PATH_ABSOLUTE."/$ttl/$file".".pass");
}
// Database for hits today
$db_csrf = new Medoo([
'database_type' => 'sqlite',
'database_file' => '/path/for/csrf_table.sqlite.db'
]);
// Delete CSRF from database to prevent resubmits
deleteCSRF($csrf_post);
// Wipe POST contents to prevent resubmits TODOJEA CHECKCHECK CHECK CHECK
unset($_POST);
$_POST = array();
} // end: else (proceed with saving)
} // end: while note_exists == 1 (filename already exists -> new one will be generated)
//***********************************************
//***********************************************
// Print message URLs etc.
echo '
Message was created successfully!
• Copy the URL below and send it to the recipient.
• The message will self-destruct after being read or after the timer expires if the message hasn\'t been read in time.
• In case you need to delete the message you just wrote, use the corresponding button.
';
// Get the wipe time/date for non-JS users (TODO somehow this requires 3 hours instead of 1 ??? time zone thing???)
/*
$wipe_date = time() + (60 * 60 * 4);
$wipe_date = DateTime::createFromFormat('U', $wipe_date);
//$wipe_date = $wipe_date->format('j.n.Y - H:i');
$wipe_date = $wipe_date->format('H:i A');
*/
echo '• The contents of this page will disappear in 1 hour.';
//Based on server time it will happen at '.$wipe_date.'.'
/*
// Print countdown timer (JavaScript)
echo $js_timer;
// Print the countdown timer (no JavaScript)
echo '
';
// Print the countdown timer (JavaScript)
echo "
";
*/
echo '
';
// Set clearnet URL to variable
$message_url_to_print = "https://".SERVER_DOMAIN_NORMAL."$relative_path_to_script"."?".$file."-".$ttl."-".$pass;
// Add mode query/switch to message URL
$message_url_to_print_clearnet = "$message_url_to_print"."-N";
// Print clearnet message URL
echo 'URL
';
// Using TOR?
if($is_tor == "1"){
// Set TOR URL to variable
$message_url_to_print_tor = "http://".SERVER_DOMAIN_TOR."$relative_path_to_script"."?".$file."-".$ttl."-".$pass;
// Add mode query/switch to message URL
$message_url_to_print_tor = "$message_url_to_print_tor"."-N";
//echo '
';
/*
// TOR disabeld temporarily
// Print TOR URL
echo '
';
// Generate random filename for stats and make sure it doesn't exist
while($stat_file_exists == "1"){
// Generation (based on random 64bit string + UNIX date -> hash to SHA256)
$stats_file = generateRandom("64");
// Filename already exists -> new one will be generated
if(file_exists(STATS_PATH_ABSOLUTE."/30/$stats_file") || strlen($stats_file) < "64"){
$stat_file_exists = "1";
}
else{
// Stat file name is unique
$stat_file_exists = "0";
// Create stats files
touch(STATS_PATH_ABSOLUTE."/1/$stats_file");
touch(STATS_PATH_ABSOLUTE."/7/$stats_file");
touch(STATS_PATH_ABSOLUTE."/30/$stats_file");
} // end of else (filename already exists -> new one will be generated)
} // end of while stat_file_exists == 1
// Wipe variables
$id = "";
$d = "";
$p = "";
$file = "";
$ttl = "";
$pass = "";
$stats_file = "";
$message_url_to_print = "";
$message_url_to_print_tor = "";
//***********************************************
//***********************************************
// Header/session thing (to prevent form resubmits)
//header("Location: "."$server_url"."$relative_path_to_script"."?create");
//exit();
}
//============================================================================================
// TODOSESSIONFIX related thing (TODO not needed ???)
// Redirect to main page if ?create is being used
elseif($query == "create"){
header("Location: "."$server_url"."$relative_path_to_script");
exit();
//============================================================================================
}
// Error: Message not found or it has already been read
elseif(!empty($d) && !empty($id) && !empty($p) && !file_exists(MESSAGE_PATH_ABSOLUTE."/$d/$id".".counter")){
echo '