diff --git a/game/diffBundle/server/protocol.txt b/game/diffBundle/server/protocol.txt deleted file mode 100644 index 2358aac5..00000000 --- a/game/diffBundle/server/protocol.txt +++ /dev/null @@ -1,66 +0,0 @@ -All returns are whitespace-delimited. - - - -=== Call: -server.php?action=is_update_available - &platform=[platform code] - &old_version==[version number] - -Returns: -size_of_update - -or - -0 - -or - -URLS -# -UPDATE A->B size -URL1 -URL2 -... -URLM -# -UPDATE B->C size -URL1 -URL2 -... -URLN -# -UPDATE C->D size -URL1 -URL2 -... -URLP -# -... - -This is for when server is set up to serve URLS to mirrors instead of .dbz -files directly. This also allows multi-step incremental updates (instead -of serving _full files to clients that have missed an update). - -The URLS tag indicates that the response contains URL batches. -The batches are delimited by # -Each batch has an "UPDATE A->B size" header, indicating that this update is -incremental from version A to version B and has a given download size, followed -by one URL mirror of that update per line. - - - - -Valid platform codes are currently "mac", "win", and "linux" - - - - -=== Call: -server.php?action=get_update - &platform=[platform code] - &old_version=[version number] - - -Serves a .dbz diff bundle file that is sufficient to update old_version -to the latest version. diff --git a/game/diffBundle/server/server.php b/game/diffBundle/server/server.php deleted file mode 100644 index 65f6aee6..00000000 --- a/game/diffBundle/server/server.php +++ /dev/null @@ -1,327 +0,0 @@ - $latestVersion ) { - $latestVersion = $matches[1]; - } - } - else if( preg_match( "/(\d+)_inc_$inPlatform.dbz/", - $file, $matches ) ) { - if( $matches[1] > $latestVersion ) { - $latestVersion = $matches[1]; - } - } - else if( preg_match( "/(\d+)_full_$inPlatform"."_urls.txt/", - $file, $matches ) ) { - - if( $matches[1] > $latestVersion ) { - $latestVersion = $matches[1]; - } - } - else if( preg_match( "/(\d+)_inc_$inPlatform"."_urls.txt/", - $file, $matches ) ) { - if( $matches[1] > $latestVersion ) { - $latestVersion = $matches[1]; - } - } - } - return $latestVersion; - } - - -function dbs_getLatestVersionAll( $inPlatform ) { - $latest = dbs_getLatestVersion( $inPlatform ); - $latestAll = dbs_getLatestVersion( "all" ); - - if( $latestAll > $latest ) { - $latest = $latestAll; - } - - global $downloadFilePath; - - $latestLimitPath = $downloadFilePath . "latest.txt"; - - if( file_exists( $latestLimitPath ) ) { - - $latestLimit = trim( file_get_contents( $latestLimitPath ) ); - - if( $latest > $latestLimit ) { - $latest = $latestLimit; - } - } - - return $latest; - } - - - - -// returns 1 or 0 based on user-supplied vars -function dbs_isUpdateAvailable() { - global $downloadFilePath; - - $platform = dbs_getPlatform(); - $oldVersion = dbs_getOldVersion(); - - $latest = dbs_getLatestVersionAll( $platform ); - - if( $latest > $oldVersion ) { - - if( file_exists( $downloadFilePath . - "$latest"."_inc_$platform"."_urls.txt" ) - || - file_exists( $downloadFilePath . - "$latest"."_inc_all"."_urls.txt" ) ) { - $result = "URLS\n#"; - - for( $i=$oldVersion+1; $i <= $latest; $i++ ) { - $a = $i - 1; - $b = $i; - - $fileContents = FALSE; - $filePath; - - if( file_exists( $downloadFilePath . - "$i"."_inc_$platform"."_urls.txt" ) ) { - - $filePath = - $downloadFilePath . "$i"."_inc_$platform"."_urls.txt"; - - $fileContents = file_get_contents( $filePath ); - } - - if( $fileContents === FALSE ) { - // failed to read - $filePath = - $downloadFilePath . "$i"."_inc_all_urls.txt"; - - $fileContents = file_get_contents( $filePath ); - } - - - if( $fileContents === FALSE ) { - // failed to read either - } - else { - $dbzPath = preg_replace('/_urls.txt/', '.dbz', $filePath ); - - $size = filesize( $dbzPath ); - $result = $result . "\nUPDATE $a->$b $size\n"; - $result = $result . trim( $fileContents ); - if( $i != $latest ) { - $result = $result . "\n#"; - } - } - } - return $result; - } - else { - $updateName; - - if( $latest == $oldVersion + 1 ) { - $updateName = "$latest"."_inc_$platform".".dbz"; - - if( filesize( $downloadFilePath . $updateName ) === FALSE ) { - $updateName = "$latest"."_inc_all".".dbz"; - } - } - else { - $updateName = "$latest"."_full_$platform".".dbz"; - - if( filesize( $downloadFilePath . $updateName ) === FALSE ) { - $updateName = "$latest"."_full_all".".dbz"; - } - } - - return filesize( $downloadFilePath . $updateName ); - } - } - else { - return 0; - } - } - - -function dbs_getUpdate() { - $platform = dbs_getPlatform(); - $oldVersion = dbs_getOldVersion(); - - $latest = dbs_getLatestVersion( $platform ); - - if( $latest <= $oldVersion ) { - echo "DENIED"; - return; - } - - $updateName; - - if( $latest == $oldVersion + 1 ) { - $updateName = "$latest"."_inc_$platform".".dbz"; - - if( filesize( $downloadFilePath . $updateName ) === FALSE ) { - $updateName = "$latest"."_inc_all".".dbz"; - } - } - else { - $updateName = "$latest"."_full_$platform".".dbz"; - - if( filesize( $downloadFilePath . $updateName ) === FALSE ) { - $updateName = "$latest"."_full_all".".dbz"; - } - } - - global $downloadFilePath; - - - $result = dbs_send_file( $downloadFilePath . $updateName ); - - - if( ! $result ) { - echo "DENIED"; - return; - } - } - - - - -/** - * Filters a $_REQUEST variable using a regex match. - * - * Returns "" (or specified default value) if there is no match. - */ -function dbs_requestFilter( $inRequestVariable, $inRegex, $inDefault = "" ) { - if( ! isset( $_REQUEST[ $inRequestVariable ] ) ) { - return $inDefault; - } - - $numMatches = preg_match( $inRegex, - $_REQUEST[ $inRequestVariable ], $matches ); - - if( $numMatches != 1 ) { - return $inDefault; - } - - return $matches[0]; - } - - - - -// found here: -// http://php.net/manual/en/function.fpassthru.php - -function dbs_send_file( $path ) { - session_write_close(); - //ob_end_clean(); - - if( !is_file( $path ) || connection_status() != 0 ) { - return( FALSE ); - } - - - //to prevent long file from getting cut off from //max_execution_time - - set_time_limit( 0 ); - - $name = basename( $path ); - - //filenames in IE containing dots will screw up the - //filename unless we add this - - // sometimes user agent is not set! - if( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { - - if( strstr( $_SERVER['HTTP_USER_AGENT'], "MSIE" ) ) { - $name = - preg_replace('/\./', '%2e', - $name, substr_count($name, '.') - 1); - } - } - - - //required, or it might try to send the serving - //document instead of the file - - header("Cache-Control: "); - header("Pragma: "); - header("Content-Type: application/octet-stream"); - header("Content-Length: " .(string)(filesize($path)) ); - header('Content-Disposition: attachment; filename="'.$name.'"'); - header("Content-Transfer-Encoding: binary\n"); - - if( $file = fopen( $path, 'rb' ) ) { - while( ( !feof( $file ) ) - && ( connection_status() == 0 ) ) { - print( fread( $file, 1024*8 ) ); - flush(); - } - fclose($file); - } - return( (connection_status() == 0 ) and !connection_aborted() ); - } - -?> \ No newline at end of file diff --git a/game/diffBundle/server/settings.php b/game/diffBundle/server/settings.php deleted file mode 100644 index e474dfa9..00000000 --- a/game/diffBundle/server/settings.php +++ /dev/null @@ -1,40 +0,0 @@ - \ No newline at end of file diff --git a/game/reviewServer/databaseUpdates.txt b/game/reviewServer/databaseUpdates.txt deleted file mode 100644 index ee00429e..00000000 --- a/game/reviewServer/databaseUpdates.txt +++ /dev/null @@ -1,13 +0,0 @@ -// add indices to columns that we search and sort by constantly - -ALTER TABLE reviewServer_user_stats ADD INDEX review_score ( review_score ); -ALTER TABLE reviewServer_user_stats ADD INDEX review_date ( review_date ); -ALTER TABLE reviewServer_user_stats ADD INDEX game_total_seconds ( game_total_seconds ); - - - -ALTER TABLE reviewServer_user_stats ADD lives_since_recent_poll INT NOT NULL AFTER review_votes; - -ALTER TABLE reviewServer_user_stats ADD seconds_lived_since_recent_poll INT NOT NULL AFTER lives_since_recent_poll; - -ALTER TABLE reviewServer_user_stats ADD recent_poll_answered TINYINT NOT NULL AFTER seconds_lived_since_recent_poll; diff --git a/game/reviewServer/footer.php b/game/reviewServer/footer.php deleted file mode 100644 index 79978e40..00000000 --- a/game/reviewServer/footer.php +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/game/reviewServer/header.php b/game/reviewServer/header.php deleted file mode 100644 index 89eecccd..00000000 --- a/game/reviewServer/header.php +++ /dev/null @@ -1,9 +0,0 @@ - - - -Sleep Is Death (Geisterfahrer) - - - - diff --git a/game/reviewServer/icons.svg b/game/reviewServer/icons.svg deleted file mode 100644 index f075663c..00000000 --- a/game/reviewServer/icons.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/game/reviewServer/index.php b/game/reviewServer/index.php deleted file mode 100644 index 894c903a..00000000 --- a/game/reviewServer/index.php +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - -
- -
- - - -
- -
- Yubikey:
- - - - - - - -
-
-Server-provided Pepper: -
- - -
-hmac_sha1 of password with pepper as key:
- - -
- - - \ No newline at end of file diff --git a/game/reviewServer/notRec.png b/game/reviewServer/notRec.png deleted file mode 100644 index 6a60ac90..00000000 Binary files a/game/reviewServer/notRec.png and /dev/null differ diff --git a/game/reviewServer/passwordHashUtility.php b/game/reviewServer/passwordHashUtility.php deleted file mode 100644 index 34ff48f0..00000000 --- a/game/reviewServer/passwordHashUtility.php +++ /dev/null @@ -1,28 +0,0 @@ - -
- - - - diff --git a/game/reviewServer/protocol.txt b/game/reviewServer/protocol.txt deleted file mode 100644 index 5c4e5a4f..00000000 --- a/game/reviewServer/protocol.txt +++ /dev/null @@ -1,184 +0,0 @@ - - - -server.php -?action=get_sequence_number -&email=[email address] - -Return: -sequence number -OK - -Gets next valid sequence number associated with email. Note that even if -email is unknown to server, 0 will be returned so that first score can be -submitted. - - - -server.php -?action=get_stats -&email=[email address] -&sequence_number=[number] -&hash_value=[hash value] - -Return: -game_count -game_total_seconds -OK --or- -DENIED - -Used by game servers to request game stats. - -hash_value is computed on both ends with: - -HMAC_SHA1( $shared_secret, $sequence_number ) - - -Where $shared_secret is a secret string known to both the reviewServer and -the game servers that have permission to request game stats. - -If sequence number is <= previously used sequence number for this email address, -request will be rejected. - - - - - -server.php -?action=log_game -&email=[email address] -&game_seconds=[integer] -&sequence_number=[number] -&hash_value=[hash value] - -Return: -OK --or- -DENIED - -Used by game servers to log game stats. - -hash_value is computed on both ends with: - -HMAC_SHA1( $shared_secret, $sequence_number ) - - -Where $shared_secret is a secret string known to both the reviewServer and -the game servers that have permission to post game stats. - -If sequence number is <= previously used sequence number for this email address, -request will be rejected. - - - - - -server.php -?action=submit_review -&email=[email address] -&review_score=[positive integer] -&review_name=[url-encoded text] -&review_text=[url-encoded text] -&hash_value=[hash value] - -Return: -OK --or- -DENIED - -Used by game clients to submit or replace user reviews. - -hash_value computed by concatonating review_score with decoded review_name and -review_text - -hash_value is computed on both ends with: - -HMAC_SHA1( $ticket_id, $review_score . - sha1( $plain_review_name ) . - sha1( $plain_review_text ) ) - - - - -server.php -?action=remove_review -&email=[email address] -&sequence_number=[number] -&hash_value=[hash value] - -Return: -OK --or- -DENIED - -Used by game clients to request review removal. - -hash_value is computed on both ends with: - -HMAC_SHA1( $ticket_id, $sequence_number ) - -If sequence number is <= previously used sequence number for this email address, -request will be rejected. - - - - - -server.php -?action=update_html - -Return: -OK - -Used by cron job to trigger regeneration of static html - - - - - - - - - -server.php -?action=check_for_poll -&email=[email address] - - -Return: -DENIED --or- -poll_id -question -answerA -answerB -answerC -... -OK - - -DENIED if no poll available for this email address - - - - -server.php -?action=poll_vote -&email=[email address] -&poll_id=id -&vote_number=number -&hash_value=[hash value] - -Return: -OK --or- -DENIED - - -Vote for answer number for a given poll. - - -Hash computed by: - -HMAC_SHA1( $ticket_id, $poll_id . "v" . $vote_number ) diff --git a/game/reviewServer/rec.png b/game/reviewServer/rec.png deleted file mode 100644 index 23fa6569..00000000 Binary files a/game/reviewServer/rec.png and /dev/null differ diff --git a/game/reviewServer/server.php b/game/reviewServer/server.php deleted file mode 100644 index 36cf93cd..00000000 --- a/game/reviewServer/server.php +++ /dev/null @@ -1,2959 +0,0 @@ - -Review Server Web-based setup - - -
- -
- -
"; - -$setup_footer = " -
-
-
-"; - - - - - - -// ensure that magic quotes are OFF -// we hand-filter all _REQUEST data with regexs before submitting it to the DB -if( get_magic_quotes_gpc() ) { - // force magic quotes to be removed - $_GET = array_map( 'rs_stripslashes_deep', $_GET ); - $_POST = array_map( 'rs_stripslashes_deep', $_POST ); - $_REQUEST = array_map( 'rs_stripslashes_deep', $_REQUEST ); - $_COOKIE = array_map( 'rs_stripslashes_deep', $_COOKIE ); - } - - - -// Check that the referrer header is this page, or kill the connection. -// Used to block XSRF attacks on state-changing functions. -// (To prevent it from being dangerous to surf other sites while you are -// logged in as admin.) -// Thanks Chris Cowan. -function rs_checkReferrer() { - global $fullServerURL; - - if( !isset($_SERVER['HTTP_REFERER']) || - strpos($_SERVER['HTTP_REFERER'], $fullServerURL) !== 0 ) { - - die( "Bad referrer header" ); - } - } - - - - -// all calls need to connect to DB, so do it once here -rs_connectToDatabase(); - -// close connection down below (before function declarations) - - -// testing: -//sleep( 5 ); - - -$maxNumAnswers = 10; - -$answerNames = array(); -$answerLetters = array( "A", "B", "C", - "D", "E", "F", - "G", "H", "I", - "J" ); -for( $i=0; $i<$maxNumAnswers; $i++ ) { - $answerNames[$i] = "answer" . $answerLetters[$i]; - } - - -// general processing whenver server.php is accessed directly - - - - -// grab POST/GET variables -$action = rs_requestFilter( "action", "/[A-Z_]+/i" ); - -$debug = rs_requestFilter( "debug", "/[01]/" ); - -$remoteIP = ""; -if( isset( $_SERVER[ "REMOTE_ADDR" ] ) ) { - $remoteIP = $_SERVER[ "REMOTE_ADDR" ]; - } - - - - -if( $action == "version" ) { - global $rs_version; - echo "$rs_version"; - } -else if( $action == "get_sequence_number" ) { - rs_getSequenceNumber(); - } -else if( $action == "get_stats" ) { - rs_getStats(); - } -else if( $action == "log_game" ) { - rs_logGame(); - } -else if( $action == "submit_review" ) { - rs_submitReview(); - } -else if( $action == "remove_review" ) { - rs_removeReview(); - } -else if( $action == "update_html" ) { - rs_updateHTML(); - } -else if( $action == "show_log" ) { - rs_showLog(); - } -else if( $action == "clear_log" ) { - rs_clearLog(); - } -else if( $action == "show_data" ) { - rs_showData(); - } -else if( $action == "regen_static_html" ) { - rs_regenStaticHTML(); - } -else if( $action == "show_detail" ) { - rs_showDetail(); - } -else if( $action == "create_poll" ) { - rs_createPoll(); - } -else if( $action == "delete_poll" ) { - rs_deletePoll(); - } -else if( $action == "check_for_poll" ) { - rs_checkForPoll(); - } -else if( $action == "poll_vote" ) { - rs_pollVote(); - } -else if( $action == "list_polls" ) { - rs_listPolls(); - } -else if( $action == "view_review" ) { - rs_viewReview(); - } -else if( $action == "list_recent" ) { - rs_listRecent(); - } -else if( $action == "list_playtime" ) { - rs_listPlaytime(); - } -else if( $action == "logout" ) { - rs_logout(); - } -else if( $action == "rs_setup" ) { - global $setup_header, $setup_footer; - echo $setup_header; - - echo "

Review Server Web-based Setup

"; - - echo "Creating tables:
"; - - echo "
-
- -
"; - - rs_setupDatabase(); - - echo "


"; - - echo $setup_footer; - } -else if( preg_match( "/server\.php/", $_SERVER[ "SCRIPT_NAME" ] ) ) { - // server.php has been called without an action parameter - - // the preg_match ensures that server.php was called directly and - // not just included by another script - - // quick (and incomplete) test to see if we should show instructions - global $tableNamePrefix; - - // check if our tables exist - $exists = rs_doesTableExist( $tableNamePrefix . "user_stats" ) && - rs_doesTableExist( $tableNamePrefix . "polls" ) && - rs_doesTableExist( $tableNamePrefix . "log" ); - - - if( $exists ) { - echo "Review Server database setup and ready"; - } - else { - // start the setup procedure - - global $setup_header, $setup_footer; - echo $setup_header; - - echo "

Review Server Web-based Setup

"; - - echo "Review Server will walk you through a " . - "brief setup process.

"; - - echo "Step 1: ". - "". - "create the database tables"; - - echo $setup_footer; - } - } - - - -// done processing -// only function declarations below - -rs_closeDatabase(); - - - - - - - -/** - * Creates the database tables needed by seedBlogs. - */ -function rs_setupDatabase() { - global $tableNamePrefix; - - $tableName = $tableNamePrefix . "log"; - if( ! rs_doesTableExist( $tableName ) ) { - - // this table contains general info about the server - // use INNODB engine so table can be locked - $query = - "CREATE TABLE $tableName(" . - "entry TEXT NOT NULL, ". - "entry_time DATETIME NOT NULL );"; - - $result = rs_queryDatabase( $query ); - - echo "$tableName table created
"; - } - else { - echo "$tableName table already exists
"; - } - - - - $tableName = $tableNamePrefix . "user_stats"; - if( ! rs_doesTableExist( $tableName ) ) { - - // this table contains general info about each ticket - $query = - "CREATE TABLE $tableName(" . - "id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT," . - "email VARCHAR(254) NOT NULL," . - "UNIQUE KEY( email )," . - "sequence_number INT NOT NULL," . - "first_game_date DATETIME NOT NULL," . - "last_game_date DATETIME NOT NULL," . - "last_game_seconds INT NOT NULL," . - "game_count INT NOT NULL," . - "game_total_seconds INT NOT NULL," . - "INDEX( game_total_seconds )," . - // -1 if not submitted yet - "review_score TINYINT NOT NULL," . - "INDEX( review_score )," . - "review_name VARCHAR(20) NOT NULL," . - "review_text TEXT NOT NULL," . - // stats about player's state when they posted the review - // they may have played more games since the review - "review_date DATETIME NOT NULL," . - "INDEX( review_date )," . - "review_game_seconds INT NOT NULL," . - "review_game_count INT NOT NULL," . - // in future, we may allow users to upvote/downvote reviews - "review_votes INT NOT NULL,". - "lives_since_recent_poll INT NOT NULL,". - "seconds_lived_since_recent_poll INT NOT NULL, ". - "recent_poll_answered TINYINT NOT NULL );"; - - $result = rs_queryDatabase( $query ); - - echo "$tableName table created
"; - } - else { - echo "$tableName table already exists
"; - } - - - - $tableName = $tableNamePrefix . "polls"; - if( ! rs_doesTableExist( $tableName ) ) { - - // this table contains general info about each ticket - $query = - "CREATE TABLE $tableName(" . - "id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT," . - "post_date DATETIME NOT NULL," . - "start_date DATETIME NOT NULL," . - "end_date DATETIME NOT NULL," . - "min_lives INT NOT NULL,". - "min_lives_since_post_date INT NOT NULL,". - "min_lived_seconds INT NOT NULL,". - "min_lived_seconds_since_post_date INT NOT NULL,". - "question TEXT NOT NULL," . - // up to 10 answers - // later answers are "" if there are fewer answers - "answerA TEXT NOT NULL," . - "answerB TEXT NOT NULL," . - "answerC TEXT NOT NULL," . - "answerD TEXT NOT NULL," . - "answerE TEXT NOT NULL," . - "answerF TEXT NOT NULL," . - "answerG TEXT NOT NULL," . - "answerH TEXT NOT NULL," . - "answerI TEXT NOT NULL," . - "answerJ TEXT NOT NULL," . - "answerA_count int NOT NULL," . - "answerB_count int NOT NULL," . - "answerC_count int NOT NULL," . - "answerD_count int NOT NULL," . - "answerE_count int NOT NULL," . - "answerF_count int NOT NULL," . - "answerG_count int NOT NULL," . - "answerH_count int NOT NULL," . - "answerI_count int NOT NULL," . - "answerJ_count int NOT NULL );"; - - $result = rs_queryDatabase( $query ); - - echo "$tableName table created
"; - } - else { - echo "$tableName table already exists
"; - } - } - - - -function rs_showLog() { - rs_checkPassword( "show_log" ); - - echo "[Main]


"; - - global $tableNamePrefix; - - $query = "SELECT * FROM $tableNamePrefix"."log ". - "ORDER BY entry_time DESC;"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - - - echo "". - "Clear log"; - - echo "
"; - - echo "$numRows log entries:


\n"; - - - for( $i=0; $i<$numRows; $i++ ) { - $time = rs_mysqli_result( $result, $i, "entry_time" ); - $entry = htmlspecialchars( rs_mysqli_result( $result, $i, "entry" ) ); - - echo "$time:
$entry
\n"; - } - } - - - -function rs_clearLog() { - rs_checkPassword( "clear_log" ); - - echo "[Main]


"; - - global $tableNamePrefix; - - $query = "DELETE FROM $tableNamePrefix"."log;"; - $result = rs_queryDatabase( $query ); - - if( $result ) { - echo "Log cleared."; - } - else { - echo "DELETE operation failed?"; - } - } - - - - - - - - - - - - - - - - - - - - -function rs_logout() { - rs_checkReferrer(); - - rs_clearPasswordCookie(); - - echo "Logged out"; - } - - - - -function rs_showData( $checkPassword = true ) { - // these are global so they work in embeded function call below - global $skip, $search, $order_by; - - if( $checkPassword ) { - rs_checkPassword( "show_data" ); - } - - global $tableNamePrefix, $remoteIP; - - - $query = "SELECT COUNT(*) ". - "FROM $tableNamePrefix"."user_stats;"; - - $result = rs_queryDatabase( $query ); - - $count = rs_mysqli_result( $result, 0, 0 ); - - $halfCount = round( $count / 2 ); - - $query = "SELECT game_total_seconds ". - "FROM $tableNamePrefix"."user_stats ORDER BY game_total_seconds DESC ". - "LIMIT $halfCount, 1;"; - - $result = rs_queryDatabase( $query ); - - $medianSec = rs_mysqli_result( $result, 0, 0 ); - - $medianTime = rs_secondsToTimeSummary( $medianSec ); - - - $query = "SELECT game_count ". - "FROM $tableNamePrefix"."user_stats ORDER BY game_count DESC ". - "LIMIT $halfCount, 1;"; - - $result = rs_queryDatabase( $query ); - - $medianGames = rs_mysqli_result( $result, 0, 0 ); - - - - - $query = - "SELECT SUM( game_total_seconds ) / COUNT(*) ". - " as average_game_total_seconds, ". - "SUM( game_count ) / COUNT(*) ". - " as average_game_count ". - "FROM $tableNamePrefix"."user_stats;"; - $result = rs_queryDatabase( $query ); - - $average_game_total_seconds = - rs_mysqli_result( $result, 0, "average_game_total_seconds" ); - - $averageTotal = rs_secondsToTimeSummary( $average_game_total_seconds ); - - $average_game_count = rs_mysqli_result( $result, 0, "average_game_count" ); - - - echo "". - "". - "". - "". - "
[Main] [". - "Regen HTML]Average: ". - "$averageTotal spent in $average_game_count games
". - "Median: $medianTime spent in $medianGames games
[Logout]



"; - - - - - $skip = rs_requestFilter( "skip", "/[0-9]+/", 0 ); - - global $usersPerPage; - - $search = rs_requestFilter( "search", "/[A-Z0-9_@. \-]+/i" ); - - $order_by = rs_requestFilter( "order_by", "/[A-Z_]+/i", - "last_game_date" ); - - $keywordClause = ""; - $searchDisplay = ""; - - if( $search != "" ) { - - - $keywordClause = "WHERE ( email LIKE '%$search%' " . - "OR id LIKE '%$search%' " . - "OR review_name LIKE '%$search%' " . - "OR review_text LIKE '%$search%' ) "; - - $searchDisplay = " matching $search"; - } - - - - - // first, count results - $query = "SELECT COUNT(*) FROM $tableNamePrefix". - "user_stats $keywordClause;"; - - $result = rs_queryDatabase( $query ); - $totalRecords = rs_mysqli_result( $result, 0, 0 ); - - - $orderDir = "DESC"; - - if( $order_by == "email" ) { - $orderDir = "ASC"; - } - - - $query = "SELECT *, ". - "TIMESTAMPDIFF( SECOND, first_game_date, last_game_date ) ". - " as play_span, ". - "ROUND( game_total_seconds / game_count ) as average_game_seconds ". - "FROM $tableNamePrefix"."user_stats $keywordClause". - "ORDER BY $order_by $orderDir ". - "LIMIT $skip, $usersPerPage;"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - $startSkip = $skip + 1; - - $endSkip = $startSkip + $usersPerPage - 1; - - if( $endSkip > $totalRecords ) { - $endSkip = $totalRecords; - } - - - - // form for searching tickets -?> -
- - - - - -
-
-\n"; - - - $nextSkip = $skip + $usersPerPage; - - $prevSkip = $skip - $usersPerPage; - - if( $prevSkip >= 0 ) { - echo "[". - "Previous Page] "; - } - if( $nextSkip < $totalRecords ) { - echo "[". - "Next Page]"; - } - - echo "

"; - - echo "\n"; - - function orderLink( $inOrderBy, $inLinkText ) { - global $skip, $search, $order_by; - if( $inOrderBy == $order_by ) { - // already displaying this order, don't show link - return "$inLinkText"; - } - - // else show a link to switch to this order - return "$inLinkText"; - } - - - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - - - for( $i=0; $i<$numRows; $i++ ) { - $email = rs_mysqli_result( $result, $i, "email" ); - $last_game_date = rs_mysqli_result( $result, $i, "last_game_date" ); - $last_game_seconds = rs_mysqli_result( $result, $i, - "last_game_seconds" ); - - $play_span = rs_mysqli_result( $result, $i, "play_span" ); - - $average_game_seconds = - rs_mysqli_result( $result, $i, "average_game_seconds" ); - - - $game_count = rs_mysqli_result( $result, $i, "game_count" ); - $game_total_seconds = rs_mysqli_result( $result, $i, - "game_total_seconds" ); - - $first_game_date = rs_mysqli_result( $result, $i, "first_game_date" ); - - $review_votes = rs_mysqli_result( $result, $i, "review_votes" ); - - $review_text = rs_mysqli_result( $result, $i, "review_text" ); - - $review_score = rs_mysqli_result( $result, $i, "review_score" ); - - $review_name = rs_mysqli_result( $result, $i, "review_name" ); - - - $lastDuration = rs_secondsToTimeSummary( $last_game_seconds ); - $totalDuration = rs_secondsToTimeSummary( $game_total_seconds ); - - $averageDuration = rs_secondsToTimeSummary( $average_game_seconds ); - - $spanDuration = rs_secondsToAgeSummary( $play_span ); - - $lastGameAgo = rs_secondsToAgeSummary( strtotime( "now" ) - - strtotime( $last_game_date ) ); - - $firstGameAgo = rs_secondsToAgeSummary( strtotime( "now" ) - - strtotime( $first_game_date ) ); - - - $oldLen = strlen( $review_text ); - - $review_text = substr( $review_text, 0, 80 ); - - if( $oldLen > 80 ) { - $review_text = $review_text . " ..."; - } - - $review_text = wordwrap( $review_text, 20, " ", true ); - - - - $encodedEmail = urlencode( $email ); - - $nameString = ""; - - if( $review_name != "" ) { - $nameString = "($review_name) "; - } - - - echo "\n"; - - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - } - echo "
".orderLink( "email", "Email" )."".orderLink( "last_game_date", "Last Game" )."".orderLink( "last_game_seconds", "Last Game Time" )."".orderLink( "game_count", "Game Count" )."".orderLink( "game_total_seconds", "Total Game Time" )."".orderLink( "average_game_seconds", - "Ave Game Time" )."".orderLink( "first_game_date", "First Game" )."".orderLink( "play_span", "Play Span" )."".orderLink( "review_votes", "Review Votes" )."Review
". - "". - "$email$last_game_date
($lastGameAgo ago)
$lastDuration$game_count$totalDuration$averageDuration$first_game_date
($firstGameAgo ago)
$spanDuration$review_votes$nameString($review_score)
$review_text
"; - - - - echo "




"; - - - - // now show polls - - $query = "SELECT COUNT(*) FROM $tableNamePrefix". - "polls;"; - - $result = rs_queryDatabase( $query ); - $totalRecords = rs_mysqli_result( $result, 0, 0 ); - - - $poll_skip = rs_requestFilter( "poll_skip", "/[0-9]+/", 0 ); - - $startSkip = $poll_skip + 1; - - $endSkip = $startSkip + $usersPerPage - 1; - - if( $endSkip > $totalRecords ) { - $endSkip = $totalRecords; - } - - echo "$totalRecords poll records". $searchDisplay . - " (showing $startSkip - $endSkip):
\n"; - - - $nextSkip = $poll_skip + $usersPerPage; - - $prevSkip = $poll_skip - $usersPerPage; - - if( $prevSkip >= 0 ) { - echo "[". - "Previous Page] "; - } - if( $nextSkip < $totalRecords ) { - echo "[". - "Next Page]"; - } - - echo "

"; - - - - $query = "SELECT * FROM $tableNamePrefix"."polls ". - "ORDER BY post_date desc ". - "LIMIT $poll_skip, $usersPerPage;"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - echo "\n"; - - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - - - global $maxNumAnswers, $answerNames; - - for( $i=0; $i<$numRows; $i++ ) { - $id = rs_mysqli_result( $result, $i, "id" ); - - $post_date = rs_mysqli_result( $result, $i, "post_date" ); - $start_date = rs_mysqli_result( $result, $i, "start_date" ); - $end_date = rs_mysqli_result( $result, $i, "end_date" ); - - $min_lives = rs_mysqli_result( $result, $i, "min_lives" ); - $min_lives_since_post_date = - rs_mysqli_result( $result, $i, "min_lives_since_post_date" ); - - $min_lived_seconds = - rs_mysqli_result( $result, $i, "min_lived_seconds" ); - $min_lived_seconds_since_post_date = - rs_mysqli_result( $result, $i, - "min_lived_seconds_since_post_date" ); - - - $question = rs_mysqli_result( $result, $i, "question" ); - - $answers = array(); - - $answerCounts = array(); - $totalCounts = 0; - - for( $a=0; $a < $maxNumAnswers; $a++ ) { - $ans = rs_mysqli_result( $result, $i, $answerNames[$a] ); - - if( $ans != "" ) { - $answers[] = $ans; - $num = rs_mysqli_result( $result, $i, - $answerNames[$a] . "_count" ); - $answerCounts[] = $num; - $totalCounts += $num; - - } - } - - echo "\n"; - - $postAgo = rs_secondsToAgeSummary( strtotime( "now" ) - - strtotime( $post_date ) ); - - echo "\n"; - - $startAgoSec = strtotime( "now" ) - strtotime( $start_date ); - - $startAgo; - - if( $startAgoSec > 0 ) { - $startAgo = rs_secondsToAgeSummary( $startAgoSec ) . " ago"; - } - else { - $startAgo = "in " . rs_secondsToAgeSummary( -$startAgoSec ); - } - - - $endAgoSec = strtotime( "now" ) - strtotime( $end_date ); - - $endAgo; - - if( $endAgoSec > 0 ) { - $endAgo = rs_secondsToAgeSummary( $endAgoSec ) . " ago"; - } - else { - $endAgo = "in " . rs_secondsToAgeSummary( -$endAgoSec ); - } - - $runTime = rs_secondsToTimeSummary( strtotime( $end_date ) - - strtotime( $start_date ) ); - - - echo "\n"; - - echo "\n"; - $livedTime = rs_secondsToTimeSummary( $min_lived_seconds ); - $livedTimeSince = - rs_secondsToTimeSummary( $min_lived_seconds_since_post_date ); - - echo "\n"; - - echo "\n"; - - echo ""; - - echo ""; - - echo "\n"; - } - echo "
Post DateStart/EndMin LivesMin Lived TimeQuestionAnswers
$post_date
($postAgo ago)
$start_date
($startAgo)

". - "to

$end_date
($endAgo)

". - "Run time: $runTime
$min_lives
($min_lives_since_post_date new)
$livedTime
($livedTimeSince new)
$question"; - - $a = 0; - foreach( $answers as $ans ) { - $percent = ( 100 * $answerCounts[$a] / $totalCounts ); - - echo "$ans : " . $answerCounts[$a] . " ($percent%)
"; - $a ++; - } - echo "
". - "". - "". - "". - "". - "
"; - - - echo "




"; - - // form for adding a new poll - - echo "Create new Poll:

" -?> -
- - Start in: - hours
- Run for: - days
- Min Lives: -
- Min Lives Since Poll Posted: -
- - Min Lived Hours: -
- Min Lived Minutes Since Poll Posted: -
- - Question:
-
- Answers:
-
"; - } - ?> - Confirm
- -
-"; - - echo "". - "Show log"; - echo "
"; - echo "Generated for $remoteIP\n"; - - } - - - -function rs_showDetail( $checkPassword = true ) { - if( $checkPassword ) { - rs_checkPassword( "show_detail" ); - } - - echo "[Main]


"; - - global $tableNamePrefix; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i" ); - - $query = "SELECT * FROM $tableNamePrefix"."user_stats ". - "WHERE email = '$email';"; - $result = rs_queryDatabase( $query ); - - $id = rs_mysqli_result( $result, 0, "id" ); - $email = rs_mysqli_result( $result, 0, "email" ); - $review_date = rs_mysqli_result( $result, 0, "review_date" ); - - $review_text = rs_mysqli_result( $result, 0, "review_text" ); - - $review_score = rs_mysqli_result( $result, 0, "review_score" ); - - $review_name = rs_mysqli_result( $result, 0, "review_name" ); - - echo "
"; - - echo "Email: $email

"; - echo "Date: $review_date

"; - echo "Name: $review_name

"; - echo "Score: $review_score

"; - - - global $fullServerURL; - - echo "View: ". - "[$id]

"; - - - $review_text = preg_replace( '/\n/', "
", $review_text ); - - $review_text = wordwrap( $review_text, 20, " ", true ); - - echo "Review:
". - "
$review_text
"; - - echo "
"; - - - } - - - - -function rs_createPoll() { - rs_checkPassword( "create_poll" ); - - - - global $tableNamePrefix, $rs_mysqlLink; - - $confirm = rs_requestFilter( "confirm", "/[01]/" ); - - - if( $confirm != 1 ) { - echo "[Main]


"; - - echo "You must check the Confirm box to create a poll\n"; - return; - } - - - $question = ""; - if( isset( $_REQUEST[ "question" ] ) ) { - $question = $_REQUEST[ "question" ]; - } - - $question = preg_replace( '/\r\n/', " ", $question ); - - $question = preg_replace( '/ /', " ", $question ); - - - $question = mysqli_real_escape_string( $rs_mysqlLink, $question ); - - $start_hours = rs_requestFilter( "start_hours", "/[0-9.]+/", 1 ); - - $run_days = rs_requestFilter( "run_days", "/[0-9.]+/", 1 ); - - $min_lives = rs_requestFilter( "min_lives", "/[0-9]+/", 10 ); - - $min_lives_since_post_date = - rs_requestFilter( "min_lives_since_post_date", "/[0-9]+/", 2 ); - - $min_lives = rs_requestFilter( "min_lives", "/[0-9]+/", 10 ); - - $min_lived_hours = - rs_requestFilter( "min_lived_hours", "/[0-9]+/", 2 ); - - $min_lived_minutes_since_post_date = - rs_requestFilter( "min_lived_minutes_since_post_date", "/[0-9]+/", 2 ); - - - $answers = array(); - - global $maxNumAnswers, $answerNames; - - for( $i=0; $i<$maxNumAnswers; $i++ ) { - $answers[$i] = ""; - - if( isset( $_REQUEST[ $answerNames[$i] ] ) ) { - $answers[$i] = $_REQUEST[ $answerNames[$i] ]; - } - - $answers[$i] = mysqli_real_escape_string( $rs_mysqlLink, $answers[$i] ); - } - - global $maxNumAnswers, $answerNames; - - $answerClause = ""; - $countClause = ""; - for( $i=0; $i<$maxNumAnswers; $i++ ) { - $answerClause = - $answerClause . - $answerNames[$i] . - " = '" . $answers[$i] . "' "; - - $countClause = $countClause . $answerNames[$i] . "_count = 0, "; - - if( $i < $maxNumAnswers - 1 ) { - $answerClause = $answerClause . " , "; - } - } - - global $tableNamePrefix; - - $query = "INSERT INTO $tableNamePrefix". "polls SET " . - "post_date = CURRENT_TIMESTAMP, ". - "start_date = DATE_ADD( CURRENT_TIMESTAMP, ". - " INTERVAL $start_hours * 3600 SECOND ), ". - "end_date = DATE_ADD( DATE_ADD( CURRENT_TIMESTAMP, ". - " INTERVAL $start_hours * 3600 SECOND ), ". - " INTERVAL $run_days * 3600 * 24 SECOND ), ". - "min_lives = $min_lives, ". - "min_lives_since_post_date = $min_lives_since_post_date, ". - "min_lived_seconds = $min_lived_hours * 3600, ". - "min_lived_seconds_since_post_date = ". - " $min_lived_minutes_since_post_date * 60, ". - "question = '$question', ". - $countClause . - $answerClause . - ";"; - - rs_log( $query ); - - rs_queryDatabase( $query ); - - - // reset lives for all users - $query = "UPDATE $tableNamePrefix". "user_stats SET " . - "lives_since_recent_poll = 0, seconds_lived_since_recent_poll = 0, ". - "recent_poll_answered = 0;"; - - rs_queryDatabase( $query ); - - - rs_showData( false ); - } - - - -function rs_deletePoll() { - rs_checkPassword( "delete_poll" ); - - - global $tableNamePrefix; - - $confirm = rs_requestFilter( "confirm", "/[01]/" ); - - if( $confirm != 1 ) { - echo "[Main]


"; - echo "You must check the Confirm box to delete a poll\n"; - return; - } - - - $id = rs_requestFilter( "id", "/[0-9]+/", -1 ); - - global $tableNamePrefix; - - rs_queryDatabase( "DELETE FROM $tableNamePrefix"."polls " . - "WHERE id = $id;" ); - - - rs_showData( false ); - } - - - - -// if $doNotPrint is true, returns active poll ID or -1 -function rs_checkForPoll( $doNotPrint = false ) { - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - - if( $email == "" ) { - if( $doNotPrint ) { - return -1; - } - - echo "DENIED"; - return; - } - - - global $tableNamePrefix; - - - $query = "SELECT * FROM $tableNamePrefix"."user_stats ". - "WHERE email = '$email';"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 0 ) { - if( $doNotPrint ) { - return -1; - } - echo "DENIED"; - return; - } - - - $game_count = - rs_mysqli_result( $result, 0, "game_count" ); - $game_total_seconds = - rs_mysqli_result( $result, 0, "game_total_seconds" ); - - - $seconds_lived_since_recent_poll = - rs_mysqli_result( $result, 0, "seconds_lived_since_recent_poll" ); - - $lives_since_recent_poll = - rs_mysqli_result( $result, 0, "lives_since_recent_poll" ); - - $recent_poll_answered = - rs_mysqli_result( $result, 0, "recent_poll_answered" ); - - if( $recent_poll_answered ) { - if( $doNotPrint ) { - return -1; - } - echo "DENIED"; - return; - } - - - $query = "SELECT * FROM $tableNamePrefix"."polls ". - "WHERE start_date <= CURRENT_TIMESTAMP AND ". - "end_date > CURRENT_TIMESTAMP AND ". - "min_lives <= $game_count AND ". - "min_lives_since_post_date <= $lives_since_recent_poll AND ". - "min_lived_seconds <= $game_total_seconds AND ". - "min_lived_seconds_since_post_date <= ". - " $seconds_lived_since_recent_poll;"; - - - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 0 ) { - if( $doNotPrint ) { - return -1; - } - echo "DENIED"; - return; - } - - $poll_id = rs_mysqli_result( $result, 0, "id" ); - - // one exists - if( $doNotPrint ) { - return $poll_id; - } - - - - echo "$poll_id\n"; - - - $question = rs_mysqli_result( $result, 0, "question" ); - - echo "$question\n"; - - - global $maxNumAnswers, $answerNames; - - for( $i=0; $i<$maxNumAnswers; $i++ ) { - $answers[$i] = ""; - - $ans = rs_mysqli_result( $result, 0, $answerNames[$i] ); - - if( $ans != "" ) { - echo "$ans\n"; - } - } - - echo "OK"; - } - - - - -function rs_pollVote() { - global $tableNamePrefix, $sharedGameServerSecret, $rs_mysqlLink; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - $poll_id = rs_requestFilter( "poll_id", "/[0-9]+/i", "0" ); - $vote_number = rs_requestFilter( "vote_number", "/[0-9]+/i", "0" ); - - $hash_value = rs_requestFilter( "hash_value", "/[A-F0-9]+/i", "" ); - - $hash_value = strtoupper( $hash_value ); - - - - - if( $email == "" ) { - rs_log( "poll_vote denied for bad email" ); - - echo "DENIED"; - return; - } - - - $stringToHash = $poll_id . "v" . $vote_number; - - - $encodedString = urlencode( $stringToHash ); - $encodedEmail = urlencode( $email ); - - global $ticketServerURL; - - $request = "$ticketServerURL". - "?action=check_ticket_hash". - "&email=$encodedEmail" . - "&hash_value=$hash_value" . - "&string_to_hash=$encodedString"; - - $result = file_get_contents( $request ); - - if( $result != "VALID" ) { - rs_log( "poll_vote denied for failed hash check " ); - - echo "DENIED"; - return; - } - - // lock table to prevent double-voiting - rs_queryDatabase( "lock tables $tableNamePrefix"."user_stats write;" ); - - - $poll_id = rs_checkForPoll( true ); - - if( $poll_id == -1 ) { - rs_log( "poll_vote denied, no poll exists" ); - - rs_queryDatabase( "unlock tables;" ); - - echo "DENIED"; - return; - } - - - $query = "UPDATE $tableNamePrefix". - "user_stats SET recent_poll_answered = 1 WHERE email = '$email';"; - - $result = rs_queryDatabase( $query ); - - rs_queryDatabase( "unlock tables;" ); - - global $maxNumAnswers, $answerNames; - - $thisAnswerName = ""; - - for( $i=0; $i<$maxNumAnswers; $i++ ) { - - if( $i == $vote_number ) { - $thisAnswerName = $answerNames[$i]; - break; - } - } - - - if( $thisAnswerName == "" ) { - rs_log( "poll_vote denied, bad answer index $vote_number" ); - - echo "DENIED"; - return; - } - - - $query = "UPDATE $tableNamePrefix". - "polls SET $thisAnswerName" . "_count = ". - "$thisAnswerName" . "_count + 1 WHERE id = $poll_id;"; - - $result = rs_queryDatabase( $query ); - - - echo "OK"; - } - - - -function rs_listPolls() { - global $header, $footer; - - eval( $header ); - - $posNeg = rs_requestFilter( "pos_neg", "/[\-01]+/i", -1 ); - $skip = rs_requestFilter( "skip", "/[0-9]+/i", 0 ); - - global $reviewPageWidth; - echo "
"; - - global $tableNamePrefix; - - $query = "SELECT * FROM $tableNamePrefix"."polls ". - "ORDER BY post_date desc;"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - - for( $i=0; $i<$numRows; $i++ ) { - $id = rs_mysqli_result( $result, $i, "id" ); - - $post_date = rs_mysqli_result( $result, $i, "post_date" ); - $start_date = rs_mysqli_result( $result, $i, "start_date" ); - $end_date = rs_mysqli_result( $result, $i, "end_date" ); - - $min_lives = rs_mysqli_result( $result, $i, "min_lives" ); - $min_lives_since_post_date = - rs_mysqli_result( $result, $i, "min_lives_since_post_date" ); - - $min_lived_seconds = - rs_mysqli_result( $result, $i, "min_lived_seconds" ); - $min_lived_seconds_since_post_date = - rs_mysqli_result( $result, $i, - "min_lived_seconds_since_post_date" ); - - - $question = rs_mysqli_result( $result, $i, "question" ); - - $answers = array(); - - $answerCounts = array(); - $totalCounts = 0; - - global $answerNames, $maxNumAnswers; - - for( $a=0; $a < $maxNumAnswers; $a++ ) { - $ans = rs_mysqli_result( $result, $i, $answerNames[$a] ); - - if( $ans != "" ) { - $answers[] = $ans; - $num = rs_mysqli_result( $result, $i, - $answerNames[$a] . "_count" ); - $answerCounts[] = $num; - $totalCounts += $num; - - } - } - - echo "". - "
"; - - $startAgoSec = strtotime( "now" ) - strtotime( $start_date ); - - $startAgo; - - if( $startAgoSec > 0 ) { - $startAgo = rs_secondsToAgeSummary( $startAgoSec ) . " ago"; - } - else { - $startAgo = "in " . rs_secondsToAgeSummary( -$startAgoSec ); - } - - $startString = date('l F j, Y g:i:s A', strtotime( $start_date ) ); - - - $runTime = rs_secondsToTimeSummary( strtotime( $end_date ) - - strtotime( $start_date ) ); - - $endHint = ""; - - $endAgoSec = strtotime( "now" ) - strtotime( $end_date ); - - if( $endAgoSec < 0 ) { - $endHint = - " (ends in " . rs_secondsToAgeSummary( -$endAgoSec ) . ")"; - } - - - echo ""; - - echo ""; - echo ""; - echo "
$startString$startAgo
Run time: $runTime". - "$endHint
"; - - echo "

"; - - - echo "Question:

"; - - echo "
"; - echo ""; - - echo "
$question
"; - - echo "
"; - - - echo "Answers:

"; - - echo "
"; - - $bgColor = "BGCOLOR=#555555"; - - $bgColorAlt = "BGCOLOR=#333333"; - - $a = 0; - - $answerCountMap = array(); - - foreach( $answers as $answer ) { - $num = $answerCounts[$a]; - - $answerCountMap[ $answer ] = $num; - $a++; - } - - arsort( $answerCountMap ); - - - foreach( $answerCountMap as $answer => $num ) { - $percent = 100 * $num / $totalCounts; - $percent = number_format( $percent, 1 ); - - echo "". - "". - ""; - - $temp = $bgColor; - $bgColor = $bgColorAlt; - $bgColorAlt = $temp; - } - echo "
$answer$num$percent %
"; - - - echo "




"; - } - - - echo "
"; - - eval( $footer ); - } - - - -// called from web UI -function rs_regenStaticHTML() { - rs_checkPassword( "regen_static_html" ); - - rs_generateRecentStatic(); - rs_generateTopPlaytimeStatic(); - rs_generateReviewCountStatic(); - - rs_showData( false ); - } - - -// called from cron job -function rs_updateHTML() { - rs_generateRecentStatic(); - rs_generateTopPlaytimeStatic(); - rs_generateReviewCountStatic(); - - echo "OK"; - } - - - -function rs_getReviewHTML( $inID, $inWidth=600, $inTextLengthLimit = -1 ) { - global $tableNamePrefix; - - $query = "SELECT * FROM $tableNamePrefix"."user_stats ". - "WHERE id = '$inID';"; - $result = rs_queryDatabase( $query ); - - $game_total_seconds = rs_mysqli_result( $result, 0, "game_total_seconds" ); - - $last_game_date = rs_mysqli_result( $result, 0, "last_game_date" ); - - $review_date = rs_mysqli_result( $result, 0, "review_date" ); - - $review_text = rs_mysqli_result( $result, 0, "review_text" ); - - $review_score = rs_mysqli_result( $result, 0, "review_score" ); - - $review_name = rs_mysqli_result( $result, 0, "review_name" ); - - - $totalDuration = rs_secondsToTimeSummary( $game_total_seconds ); - - - $lastGameAgo = rs_secondsToAgeSummary( strtotime( "now" ) - - strtotime( $last_game_date ) ); - - $reviewAgo = rs_secondsToAgeSummary( strtotime( "now" ) - - strtotime( $review_date ) ); - - global $recIcon, $notRecIcon, $fullServerURL; - - $icon = $recIcon; - - $recText = "Recommended"; - - if( $review_score == 0 ) { - $icon = $notRecIcon; - $recText = "Not Recommended"; - } - - $text = ""; - - - if( $inWidth >= 500 ) { - // full width view - $text= $text. - "". - ""; - } - else { - // compact view - $text= $text. - "". - ""; - } - - $review_text = preg_replace( '/\n/', "
", $review_text ); - - $bottomLink = ""; - - if( $inTextLengthLimit != -1 ) { - if( strlen( $review_text ) > $inTextLengthLimit ) { - $review_text = substr( $review_text, 0, $inTextLengthLimit ); - - $review_text = $review_text . "..."; - - global $fullServerURL; - $bottomLink = - "
[". - "Read more]
"; - } - } - - $text = $text . - "". - "
". - "". - "". - "". - "". - "
$recTextby $review_name
". - "$totalDuration on record
". - "". - "". - "". - "
$recText
". - "$review_name ". - "($totalDuration on record)
". - ""; - - if( $inWidth >= 500 ) { - $text = $text . - "". - "
Posted $reviewAgo agoLast Played $lastGameAgo ago
"; - } - else { - $text = $text . - "
Posted $reviewAgo ago
"; - } - - - $review_text = wordwrap( $review_text, 20, " ", true ); - - $text = $text . - "

". - "$review_text$bottomLink"; - - return $text; - } - - - -// pass in full ORDER BY clause -// $inPosNeg is 1 or 0, only pos/neg reviews will be shown -// -1 to show all -// $inFractionList 1 means list length modulated by fraction of positive -// or negative reviews -function rs_getListHTML( $inOrderBy, $inAction, $inWidth = -1, - $inSkip=0, $inPosNeg=-1, - $inFractionList = 0 ) { - - global $tableNamePrefix, $reviewListLength, $summaryTextLength, - $reviewListWidth; - - - if( $inWidth == -1 ) { - $inWidth = $reviewListWidth; - } - - $posNegClause = ""; - - if( $inPosNeg != -1 ) { - $posNegClause = "AND review_score = $inPosNeg"; - } - - - $displayListLength = $reviewListLength; - - - if( $inPosNeg != -1 && $inFractionList ) { - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."user_stats ". - "WHERE review_score != -1;"; - $result = rs_queryDatabase( $query ); - - $count = rs_mysqli_result( $result, 0, 0 ); - - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."user_stats ". - "WHERE review_score = 1;"; - $result = rs_queryDatabase( $query ); - - - $posCount = rs_mysqli_result( $result, 0, 0 ); - - - $fraction = $posCount / $count; - - if( $inPosNeg == 1 ) { - $displayListLength = $fraction * $displayListLength; - } - else { - $displayListLength = (1 - $fraction ) * $displayListLength; - } - - // extend list by 1 - // most lists have at least 2, then, if positive fraction < 1.00 - $displayListLength = ceil( $displayListLength ) + 1; - } - - - $query = "SELECT id FROM $tableNamePrefix"."user_stats ". - "WHERE review_score != -1 $posNegClause ". - "$inOrderBy LIMIT $inSkip, $displayListLength;"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - $totalText = ""; - - for( $i=0; $i<$numRows; $i++ ) { - $id = rs_mysqli_result( $result, $i, "id" ); - - $text = rs_getReviewHTML( $id, $inWidth, $summaryTextLength ); - - $totalText = $totalText . $text . "
"; - - if( $inWidth >= 500 ) { - $totalText = $totalText . "
"; - } - } - - // next/prev widget on bottom - - $widgetText = ""; - - global $fullServerURL; - - $prevShown = false; - - if( $inSkip > 0 ) { - $prev = $inSkip - $displayListLength; - if( $prev < 0 ) { - $prev = 0; - } - $widgetText = $widgetText . - ""; - - $prevShown = true; - } - - $next = $inSkip + $displayListLength; - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."user_stats ". - "WHERE review_score != -1 $posNegClause ". - "$inOrderBy;"; - $result = rs_queryDatabase( $query ); - - $count = rs_mysqli_result( $result, 0, 0 ); - - if( $count > $next ) { - if( $prevShown ) { - $widgetText = $widgetText . - ""; - } - else { - $widgetText = $widgetText . - ""; - } - } - - $widgetText = $widgetText . "
[Prev Page]". - "[". - "Next Page][". - "More Reviews]
"; - - - $totalText = $totalText . $widgetText; - - - return $totalText; - } - - - -function rs_getRecentReviewHTML( $inWidth, $inSkip, $inPosNeg = -1, - $inFractionList = 0 ) { - return rs_getListHTML( "ORDER BY review_date DESC", - "list_recent", $inWidth, $inSkip, $inPosNeg, - $inFractionList ); - } - - -function rs_getTopPlaytimeReviewHTML( $inWidth, $inSkip, $inPosNeg = -1, - $inFractionList = 0 ) { - return rs_getListHTML( "ORDER BY game_total_seconds DESC", - "list_playtime", $inWidth, $inSkip, $inPosNeg, - $inFractionList ); - } - - - -function rs_listRecent() { - global $header, $footer; - - eval( $header ); - - $posNeg = rs_requestFilter( "pos_neg", "/[\-01]+/i", -1 ); - $skip = rs_requestFilter( "skip", "/[0-9]+/i", 0 ); - - echo "
"; - - global $reviewPageWidth; - - $text = rs_getRecentReviewHTML( $reviewPageWidth, $skip, $posNeg ); - - echo $text; - - echo "
"; - - eval( $footer ); - } - - - -function rs_listPlaytime() { - global $header, $footer; - - eval( $header ); - - $posNeg = rs_requestFilter( "pos_neg", "/[\-01]+/i", -1 ); - $skip = rs_requestFilter( "skip", "/[0-9]+/i", 0 ); - - echo "
"; - - global $reviewPageWidth; - - $text = rs_getTopPlaytimeReviewHTML( $reviewPageWidth, $skip, $posNeg ); - - echo $text; - - echo "
"; - - eval( $footer ); - } - - - -// saves HTML to disk -function rs_generateRecentStatic() { - $text = rs_getRecentReviewHTML( -1, 0 ); - - global $outputPathRecent; - - file_put_contents ( $outputPathRecent, $text ); - - $text = rs_getRecentReviewHTML( -1, 0, 1, 1 ); - - global $outputPathRecentPositive; - - file_put_contents ( $outputPathRecentPositive, $text ); - - $text = rs_getRecentReviewHTML( -1, 0, 0, 1 ); - - global $outputPathRecentNegative; - - file_put_contents ( $outputPathRecentNegative, $text ); - } - - -function rs_generateTopPlaytimeStatic() { - $text = rs_getTopPlaytimeReviewHTML( -1, 0 ); - - global $outputPathPlaytime; - - file_put_contents ( $outputPathPlaytime, $text ); - - - $text = rs_getTopPlaytimeReviewHTML( -1, 0, 1, 1 ); - - global $outputPathPlaytimePositive; - - file_put_contents ( $outputPathPlaytimePositive, $text ); - - - $text = rs_getTopPlaytimeReviewHTML( -1, 0, 0, 1 ); - - global $outputPathPlaytimeNegative; - - file_put_contents ( $outputPathPlaytimeNegative, $text ); - } - - - -function rs_generateReviewCountStatic() { - global $tableNamePrefix; - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."user_stats ". - "WHERE review_score != -1;"; - $result = rs_queryDatabase( $query ); - - $count = rs_mysqli_result( $result, 0, 0 ); - - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."user_stats ". - "WHERE review_score = 1;"; - $result = rs_queryDatabase( $query ); - - - $posCount = rs_mysqli_result( $result, 0, 0 ); - - - $fraction = $posCount / $count; - $negCount = $count - $posCount; - - $percent = ceil( $fraction * 100 ); - $negPercent = 100 - $percent; - - $text = ""; - - global $outputReviewCountPHP; - - file_put_contents ( $outputReviewCountPHP, $text ); - } - - - - - -function rs_viewReview() { - global $header, $footer; - - eval( $header ); - - $id = rs_requestFilter( "id", "/[0-9]+/i", 0 ); - $w = rs_requestFilter( "w", "/[0-9]+/i", 600 ); - - echo "
"; - - global $reviewPageWidth; - - $text = rs_getReviewHTML( $id, $reviewPageWidth, -1 ); - - echo $text; - - echo "
"; - - eval( $footer ); - } - - - - -function rs_getSequenceNumber() { - global $tableNamePrefix; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - - if( $email == "" ) { - echo "DENIED"; - return; - } - - - $seq = rs_getSequenceNumberForEmail( $email ); - - echo "$seq\n"."OK"; - } - - - -// assumes already-filtered, valid email -// returns 0 if not found -function rs_getSequenceNumberForEmail( $inEmail ) { - global $tableNamePrefix; - - $query = "SELECT sequence_number FROM $tableNamePrefix"."user_stats ". - "WHERE email = '$inEmail';"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows < 1 ) { - return 0; - } - else { - return rs_mysqli_result( $result, 0, "sequence_number" ); - } - } - - - -function rs_logGame() { - global $tableNamePrefix, $sharedGameServerSecret; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - $game_seconds = rs_requestFilter( "game_seconds", "/[0-9]+/i", "0" ); - $sequence_number = rs_requestFilter( "sequence_number", "/[0-9]+/i", "0" ); - - $hash_value = rs_requestFilter( "hash_value", "/[A-F0-9]+/i", "" ); - - $hash_value = strtoupper( $hash_value ); - - - if( $email == "" || - $game_seconds == 0 ) { - - rs_log( "logGame denied for bad email or game_seconds" ); - - echo "DENIED"; - return; - } - - $trueSeq = rs_getSequenceNumberForEmail( $email ); - - if( $trueSeq > $sequence_number ) { - rs_log( "logGame denied for stale sequence number" ); - - echo "DENIED"; - return; - } - - $computedHashValue = - strtoupper( rs_hmac_sha1( $sharedGameServerSecret, $sequence_number ) ); - - if( $computedHashValue != $hash_value ) { - rs_log( "logGame denied for bad hash value" ); - - echo "DENIED"; - return; - } - - if( $trueSeq == 0 ) { - // no record exists, add one - $query = "INSERT INTO $tableNamePrefix". "user_stats SET " . - "email = '$email', ". - "sequence_number = $sequence_number + 1, ". - "first_game_date = CURRENT_TIMESTAMP, ". - "last_game_date = CURRENT_TIMESTAMP, ". - "last_game_seconds = $game_seconds, ". - "game_count = 1,". - "game_total_seconds = $game_seconds,". - "review_score = -1, ". - "review_name = '',". - "review_text = '',". - "review_date = CURRENT_TIMESTAMP,". - "review_game_seconds = 0,". - "review_game_count=0,". - "review_votes = 0,". - "lives_since_recent_poll = 1,". - "seconds_lived_since_recent_poll = $game_seconds,". - "recent_poll_answered = 0;"; - } - else { - // update the existing one - $query = "UPDATE $tableNamePrefix"."user_stats SET " . - "sequence_number = $sequence_number + 1, ". - "game_count = game_count + 1, " . - "game_total_seconds = game_total_seconds + $game_seconds, " . - "last_game_date = CURRENT_TIMESTAMP, " . - "last_game_seconds = $game_seconds, " . - "lives_since_recent_poll = lives_since_recent_poll + 1, " . - "seconds_lived_since_recent_poll = ". - " seconds_lived_since_recent_poll + $game_seconds " . - "WHERE email = '$email'; "; - - } - - rs_queryDatabase( $query ); - - // recent reviews won't change, but top playtime might - - // still, regenerate them all so that the Posted On timestamps - // will update - rs_generateRecentStatic(); - rs_generateTopPlaytimeStatic(); - rs_generateReviewCountStatic(); - - echo "OK"; - } - - - -function rs_getStats() { - global $tableNamePrefix, $sharedGameServerSecret; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - $sequence_number = rs_requestFilter( "sequence_number", "/[0-9]+/i", "0" ); - - $hash_value = rs_requestFilter( "hash_value", "/[A-F0-9]+/i", "" ); - - $hash_value = strtoupper( $hash_value ); - - - if( $email == "" ) { - - rs_log( "getStats denied for bad email" ); - - echo "DENIED"; - return; - } - - $trueSeq = rs_getSequenceNumberForEmail( $email ); - - if( $trueSeq > $sequence_number ) { - rs_log( "getStats denied for stale sequence number" ); - - echo "DENIED"; - return; - } - - $computedHashValue = - strtoupper( rs_hmac_sha1( $sharedGameServerSecret, $sequence_number ) ); - - if( $computedHashValue != $hash_value ) { - rs_log( "getStats denied for bad hash value" ); - - echo "DENIED"; - return; - } - - $game_count = 0; - $game_total_seconds = 0; - - - if( $trueSeq == 0 ) { - // no record exists.... - // don't add one for now - - // when user doesn't exist, it's fine to keep returning - // 0 sequence number for them - } - else { - // update the existing seq # - $query = "UPDATE $tableNamePrefix"."user_stats SET " . - "sequence_number = $sequence_number + 1 ". - "WHERE email = '$email'; "; - rs_queryDatabase( $query ); - - $query = "SELECT game_count, game_total_seconds ". - "FROM $tableNamePrefix"."user_stats ". - "WHERE email = '$email'; "; - - $result = rs_queryDatabase( $query ); - $numRows = mysqli_num_rows( $result ); - - - if( $numRows == 1 ) { - - $game_count = rs_mysqli_result( $result, 0, "game_count" ); - $game_total_seconds = - rs_mysqli_result( $result, 0, "game_total_seconds" ); - } - } - - - echo "$game_count\n$game_total_seconds\n"; - echo "OK"; - } - - - - - - - -function rs_submitReview() { - global $tableNamePrefix, $sharedGameServerSecret, $rs_mysqlLink; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - $review_score = rs_requestFilter( "review_score", "/[0-9]+/i", "0" ); - - $review_name = rs_requestFilter( "review_name", "/[A-Z0-9._\- ]+/i", "" ); - - $review_text_RAW = $_REQUEST[ "review_text" ]; - - $slashedText = mysqli_real_escape_string( $rs_mysqlLink, $review_text_RAW ); - - $hash_value = rs_requestFilter( "hash_value", "/[A-F0-9]+/i", "" ); - - $hash_value = strtoupper( $hash_value ); - - - - - if( $email == "" ) { - rs_log( "submitReview denied for bad email" ); - - echo "DENIED"; - return; - } - - - $textSHA1 = strtoupper( sha1( $review_text_RAW ) ); - $nameSHA1 = strtoupper( sha1( $review_name ) ); - - $stringToHash = $review_score . $nameSHA1 . $textSHA1; - - - $encodedString = urlencode( $stringToHash ); - $encodedEmail = urlencode( $email ); - - global $ticketServerURL; - - $request = "$ticketServerURL". - "?action=check_ticket_hash". - "&email=$encodedEmail" . - "&hash_value=$hash_value" . - "&string_to_hash=$encodedString"; - - $result = file_get_contents( $request ); - - if( $result != "VALID" ) { - rs_log( "submitReview denied for failed hash check " ); - - echo "DENIED"; - return; - } - - $query = "SELECT COUNT(*) FROM $tableNamePrefix". - "user_stats WHERE email = '$email';"; - - $result = rs_queryDatabase( $query ); - $count = rs_mysqli_result( $result, 0, 0 ); - - if( $count == 0 ) { - // can post review with no games logged - $query = "INSERT INTO $tableNamePrefix". "user_stats SET " . - "email = '$email', ". - "sequence_number = 1, ". - "first_game_date = CURRENT_TIMESTAMP, ". - "last_game_date = CURRENT_TIMESTAMP, ". - "last_game_seconds = 0, ". - "game_count = 0,". - "game_total_seconds = 0,". - "review_score = $review_score, ". - "review_name = '$review_name',". - "review_text = '$slashedText',". - "review_date = CURRENT_TIMESTAMP,". - "review_game_seconds = 0,". - "review_game_count=0,". - "review_votes = 0,". - "lives_since_recent_poll = 0,". - "seconds_lived_since_recent_poll = 0,". - "recent_poll_answered = 0;"; - } - else { - // update the existing one - $query = "UPDATE $tableNamePrefix"."user_stats SET " . - "review_score = $review_score, ". - "review_name = '$review_name', ". - "review_text = '$slashedText', ". - "review_date = CURRENT_TIMESTAMP,". - "review_game_count = game_count,". - "review_game_seconds = game_total_seconds ". - "WHERE email = '$email'; "; - } - - rs_queryDatabase( $query ); - - rs_generateRecentStatic(); - rs_generateTopPlaytimeStatic(); - rs_generateReviewCountStatic(); - - echo "OK"; - } - - - - -function rs_removeReview() { - global $tableNamePrefix, $rs_mysqlLink; - - - $email = rs_requestFilter( "email", "/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+/i", "" ); - - $sequence_number = rs_requestFilter( "sequence_number", "/[0-9]+/i", "0" ); - - $hash_value = rs_requestFilter( "hash_value", "/[A-F0-9]+/i", "" ); - - $hash_value = strtoupper( $hash_value ); - - - if( $email == "" ) { - rs_log( "removeReview denied for bad email" ); - - echo "DENIED"; - return; - } - - $trueSeq = rs_getSequenceNumberForEmail( $email ); - - if( $trueSeq > $sequence_number || $trueSeq == 0 ) { - // stale sequence number or user doesn't exist in DB - rs_log( "removeReview denied for stale sequence number" ); - - echo "DENIED"; - return; - } - - - $stringToHash = $sequence_number; - - - $encodedString = urlencode( $stringToHash ); - $encodedEmail = urlencode( $email ); - - global $ticketServerURL; - - $result = file_get_contents( - "$ticketServerURL". - "?action=check_ticket_hash". - "&email=$encodedEmail" . - "&hash_value=$hash_value" . - "&string_to_hash=$encodedString" ); - - if( $result != "VALID" ) { - rs_log( "removeReview denied for failed hash check" ); - - echo "DENIED"; - return; - } - - // just set score as -1 - // keep old review text in place for reference - - $query = "UPDATE $tableNamePrefix"."user_stats SET " . - "sequence_number = $sequence_number + 1, ". - "review_score = -1 ". - "WHERE email = '$email'; "; - - rs_queryDatabase( $query ); - - rs_generateRecentStatic(); - rs_generateTopPlaytimeStatic(); - rs_generateReviewCountStatic(); - - echo "OK"; - } - - - -$rs_mysqlLink; - - -// general-purpose functions down here, many copied from seedBlogs - -/** - * Connects to the database according to the database variables. - */ -function rs_connectToDatabase() { - global $databaseServer, - $databaseUsername, $databasePassword, $databaseName, - $rs_mysqlLink; - - - $rs_mysqlLink = - mysqli_connect( $databaseServer, $databaseUsername, $databasePassword ) - or rs_operationError( "Could not connect to database server: " . - mysqli_error( $rs_mysqlLink ) ); - - mysqli_select_db( $rs_mysqlLink, $databaseName ) - or rs_operationError( "Could not select $databaseName database: " . - mysqli_error( $rs_mysqlLink ) ); - } - - - -/** - * Closes the database connection. - */ -function rs_closeDatabase() { - global $rs_mysqlLink; - - mysqli_close( $rs_mysqlLink ); - } - - -/** - * Returns human-readable summary of a timespan. - * Examples: 10.5 hours - * 34 minutes - * 45 seconds - */ -function rs_secondsToTimeSummary( $inSeconds ) { - if( $inSeconds < 120 ) { - if( $inSeconds == 1 ) { - return "$inSeconds second"; - } - return "$inSeconds seconds"; - } - else if( $inSeconds < 3600 ) { - $min = number_format( $inSeconds / 60, 0 ); - - if( $min == 1 ) { - return "$min minute"; - } - - return "$min minutes"; - } - else { - $hours = number_format( $inSeconds / 3600, 1 ); - - if( $hours == 1 ) { - return "$hours hour"; - } - - return "$hours hours"; - } - } - - -/** - * Returns human-readable summary of a distance back in time. - * Examples: 10 hours - * 34 minutes - * 45 seconds - * 19 days - * 3 months - * 2.5 years - */ -function rs_secondsToAgeSummary( $inSeconds ) { - if( $inSeconds < 120 ) { - return "$inSeconds seconds"; - } - else if( $inSeconds < 3600 * 2 ) { - $min = number_format( $inSeconds / 60, 0 ); - return "$min minutes"; - } - else if( $inSeconds < 24 * 3600 * 2 ) { - $hours = number_format( $inSeconds / 3600, 0 ); - return "$hours hours"; - } - else if( $inSeconds < 24 * 3600 * 60 ) { - $days = number_format( $inSeconds / ( 3600 * 24 ), 0 ); - return "$days days"; - } - else if( $inSeconds < 24 * 3600 * 365 * 2 ) { - // average number of days per month - // based on 400 year calendar cycle - // we skip a leap year every 100 years unless the year is divisible by 4 - $months = number_format( $inSeconds / ( 3600 * 24 * 30.436875 ), 0 ); - return "$months months"; - } - else { - // same logic behind computing average length of a year - $years = number_format( $inSeconds / ( 3600 * 24 * 365.2425 ), 1 ); - return "$years years"; - } - } - - - -/** - * Queries the database, and dies with an error message on failure. - * - * @param $inQueryString the SQL query string. - * - * @return a result handle that can be passed to other mysql functions. - */ -function rs_queryDatabase( $inQueryString ) { - global $rs_mysqlLink; - - if( gettype( $rs_mysqlLink ) != "resource" ) { - // not a valid mysql link? - rs_connectToDatabase(); - } - - $result = mysqli_query( $rs_mysqlLink, $inQueryString ); - - if( $result == FALSE ) { - - $errorNumber = mysqli_errno( $rs_mysqlLink ); - - // server lost or gone? - if( $errorNumber == 2006 || - $errorNumber == 2013 || - // access denied? - $errorNumber == 1044 || - $errorNumber == 1045 || - // no db selected? - $errorNumber == 1046 ) { - - // connect again? - rs_closeDatabase(); - rs_connectToDatabase(); - - $result = mysqli_query( $rs_mysqlLink, $inQueryString ) - or rs_operationError( - "Database query failed:
$inQueryString

" . - mysqli_error( $rs_mysqlLink ) ); - } - else { - // some other error (we're still connected, so we can - // add log messages to database - rs_fatalError( "Database query failed:
$inQueryString

" . - mysqli_error( $rs_mysqlLink ) ); - } - } - - return $result; - } - - - -/** - * Replacement for the old mysql_result function. - */ -function rs_mysqli_result( $result, $number, $field=0 ) { - mysqli_data_seek( $result, $number ); - $row = mysqli_fetch_array( $result ); - return $row[ $field ]; - } - - - -/** - * Checks whether a table exists in the currently-connected database. - * - * @param $inTableName the name of the table to look for. - * - * @return 1 if the table exists, or 0 if not. - */ -function rs_doesTableExist( $inTableName ) { - // check if our table exists - $tableExists = 0; - - $query = "SHOW TABLES"; - $result = rs_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - - for( $i=0; $i<$numRows && ! $tableExists; $i++ ) { - - $tableName = rs_mysqli_result( $result, $i, 0 ); - - if( $tableName == $inTableName ) { - $tableExists = 1; - } - } - return $tableExists; - } - - - -function rs_log( $message ) { - global $enableLog, $tableNamePrefix, $rs_mysqlLink; - - if( $enableLog ) { - $slashedMessage = mysqli_real_escape_string( $rs_mysqlLink, $message ); - - $query = "INSERT INTO $tableNamePrefix"."log VALUES ( " . - "'$slashedMessage', CURRENT_TIMESTAMP );"; - $result = rs_queryDatabase( $query ); - } - } - - - -/** - * Displays the error page and dies. - * - * @param $message the error message to display on the error page. - */ -function rs_fatalError( $message ) { - //global $errorMessage; - - // set the variable that is displayed inside error.php - //$errorMessage = $message; - - //include_once( "error.php" ); - - // for now, just print error message - $logMessage = "Fatal error: $message"; - - echo( $logMessage ); - - rs_log( $logMessage ); - - die(); - } - - - -/** - * Displays the operation error message and dies. - * - * @param $message the error message to display. - */ -function rs_operationError( $message ) { - - // for now, just print error message - echo( "ERROR: $message" ); - die(); - } - - -/** - * Recursively applies the addslashes function to arrays of arrays. - * This effectively forces magic_quote escaping behavior, eliminating - * a slew of possible database security issues. - * - * @inValue the value or array to addslashes to. - * - * @return the value or array with slashes added. - */ -function rs_addslashes_deep( $inValue ) { - return - ( is_array( $inValue ) - ? array_map( 'rs_addslashes_deep', $inValue ) - : addslashes( $inValue ) ); - } - - - -/** - * Recursively applies the stripslashes function to arrays of arrays. - * This effectively disables magic_quote escaping behavior. - * - * @inValue the value or array to stripslashes from. - * - * @return the value or array with slashes removed. - */ -function rs_stripslashes_deep( $inValue ) { - return - ( is_array( $inValue ) - ? array_map( 'rs_stripslashes_deep', $inValue ) - : stripslashes( $inValue ) ); - } - - - -/** - * Filters a $_REQUEST variable using a regex match. - * - * Returns "" (or specified default value) if there is no match. - */ -function rs_requestFilter( $inRequestVariable, $inRegex, $inDefault = "" ) { - if( ! isset( $_REQUEST[ $inRequestVariable ] ) ) { - return $inDefault; - } - - return rs_filter( $_REQUEST[ $inRequestVariable ], $inRegex, $inDefault ); - } - - -/** - * Filters a value using a regex match. - * - * Returns "" (or specified default value) if there is no match. - */ -function rs_filter( $inValue, $inRegex, $inDefault = "" ) { - - $numMatches = preg_match( $inRegex, - $inValue, $matches ); - - if( $numMatches != 1 ) { - return $inDefault; - } - - return $matches[0]; - } - - - -// this function checks the password directly from a request variable -// or via hash from a cookie. -// -// It then sets a new cookie for the next request. -// -// This avoids storing the password itself in the cookie, so a stale cookie -// (cached by a browser) can't be used to figure out the password and log in -// later. -function rs_checkPassword( $inFunctionName ) { - $password = ""; - $password_hash = ""; - - $badCookie = false; - - - global $accessPasswords, $tableNamePrefix, $remoteIP, $enableYubikey, - $passwordHashingPepper; - - $cookieName = $tableNamePrefix . "cookie_password_hash"; - - $passwordSent = false; - - if( isset( $_REQUEST[ "passwordHMAC" ] ) ) { - $passwordSent = true; - - // already hashed client-side on login form - // hash again, because hash client sends us is not stored in - // our settings file - $password = rs_hmac_sha1( $passwordHashingPepper, - $_REQUEST[ "passwordHMAC" ] ); - - - // generate a new hash cookie from this password - $newSalt = time(); - $newHash = md5( $newSalt . $password ); - - $password_hash = $newSalt . "_" . $newHash; - } - else if( isset( $_COOKIE[ $cookieName ] ) ) { - rs_checkReferrer(); - $password_hash = $_COOKIE[ $cookieName ]; - - // check that it's a good hash - - $hashParts = preg_split( "/_/", $password_hash ); - - // default, to show in log message on failure - // gets replaced if cookie contains a good hash - $password = "(bad cookie: $password_hash)"; - - $badCookie = true; - - if( count( $hashParts ) == 2 ) { - - $salt = $hashParts[0]; - $hash = $hashParts[1]; - - foreach( $accessPasswords as $truePassword ) { - $trueHash = md5( $salt . $truePassword ); - - if( $trueHash == $hash ) { - $password = $truePassword; - $badCookie = false; - } - } - - } - } - else { - // no request variable, no cookie - // cookie probably expired - $badCookie = true; - $password_hash = "(no cookie. expired?)"; - } - - - - if( ! in_array( $password, $accessPasswords ) ) { - - if( ! $badCookie ) { - - echo "Incorrect password."; - - rs_log( "Failed $inFunctionName access with password: ". - "$password" ); - } - else { - echo "Session expired."; - - rs_log( "Failed $inFunctionName access with bad cookie: ". - "$password_hash" ); - } - - die(); - } - else { - - if( $passwordSent && $enableYubikey ) { - global $yubikeyIDs, $yubicoClientID, $yubicoSecretKey, - $passwordHashingPepper; - - $yubikey = $_REQUEST[ "yubikey" ]; - - $index = array_search( $password, $accessPasswords ); - $yubikeyIDList = preg_split( "/:/", $yubikeyIDs[ $index ] ); - - $providedID = substr( $yubikey, 0, 12 ); - - if( ! in_array( $providedID, $yubikeyIDList ) ) { - echo "Provided Yubikey does not match ID for this password."; - die(); - } - - - $nonce = rs_hmac_sha1( $passwordHashingPepper, uniqid() ); - - $callURL = - "https://api2.yubico.com/wsapi/2.0/verify?id=$yubicoClientID". - "&otp=$yubikey&nonce=$nonce"; - - $result = trim( file_get_contents( $callURL ) ); - - $resultLines = preg_split( "/\s+/", $result ); - - sort( $resultLines ); - - $resultPairs = array(); - - $messageToSignParts = array(); - - foreach( $resultLines as $line ) { - // careful here, because = is used in base-64 encoding - // replace first = in a line (the key/value separator) - // with # - - $lineToParse = preg_replace( '/=/', '#', $line, 1 ); - - // now split on # instead of = - $parts = preg_split( "/#/", $lineToParse ); - - $resultPairs[$parts[0]] = $parts[1]; - - if( $parts[0] != "h" ) { - // include all but signature in message to sign - $messageToSignParts[] = $line; - } - } - $messageToSign = implode( "&", $messageToSignParts ); - - $trueSig = - base64_encode( - hash_hmac( 'sha1', - $messageToSign, - // need to pass in raw key - base64_decode( $yubicoSecretKey ), - true) ); - - if( $trueSig != $resultPairs["h"] ) { - echo "Yubikey authentication failed.
"; - echo "Bad signature from authentication server
"; - die(); - } - - $status = $resultPairs["status"]; - if( $status != "OK" ) { - echo "Yubikey authentication failed: $status"; - die(); - } - - } - - // set cookie again, renewing it, expires in 24 hours - $expireTime = time() + 60 * 60 * 24; - - setcookie( $cookieName, $password_hash, $expireTime, "/" ); - } - } - - - - -function rs_clearPasswordCookie() { - global $tableNamePrefix; - - $cookieName = $tableNamePrefix . "cookie_password_hash"; - - // expire 24 hours ago (to avoid timezone issues) - $expireTime = time() - 60 * 60 * 24; - - setcookie( $cookieName, "", $expireTime, "/" ); - } - - - - - - - - - -function rs_hmac_sha1( $inKey, $inData ) { - return hash_hmac( "sha1", - $inData, $inKey ); - } - - -function rs_hmac_sha1_raw( $inKey, $inData ) { - return hash_hmac( "sha1", - $inData, $inKey, true ); - } - - - - - - -// decodes a ASCII hex string into an array of 0s and 1s -function rs_hexDecodeToBitString( $inHexString ) { - $digits = str_split( $inHexString ); - - $bitString = ""; - - foreach( $digits as $digit ) { - $index = hexdec( $digit ); - - $binDigitString = decbin( $index ); - - // pad with 0s - $binDigitString = - substr( "0000", 0, 4 - strlen( $binDigitString ) ) . - $binDigitString; - - $bitString = $bitString . $binDigitString; - } - - return $bitString; - } - - - - -?> diff --git a/game/reviewServer/settings.php b/game/reviewServer/settings.php deleted file mode 100644 index 11f9be78..00000000 --- a/game/reviewServer/settings.php +++ /dev/null @@ -1,170 +0,0 @@ - \ No newline at end of file diff --git a/game/reviewServer/sha1.js b/game/reviewServer/sha1.js deleted file mode 100644 index 491981c0..00000000 --- a/game/reviewServer/sha1.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - A JavaScript implementation of the SHA family of hashes, as - defined in FIPS PUB 180-4 and FIPS PUB 202, as well as the corresponding - HMAC implementation as defined in FIPS PUB 198a - - Copyright Brian Turek 2008-2016 - Distributed under the BSD License - See http://caligatio.github.com/jsSHA/ for more information - - Several functions taken from Paul Johnston -*/ -'use strict';(function(G){function t(e,a,d){var g=0,c=[],b=0,f,k,l,h,m,w,n,y,p=!1,q=[],t=[],v,u=!1;d=d||{};f=d.encoding||"UTF8";v=d.numRounds||1;l=z(a,f);if(v!==parseInt(v,10)||1>v)throw Error("numRounds must a integer >= 1");if("SHA-1"===e)m=512,w=A,n=H,h=160,y=function(a){return a.slice()};else throw Error("Chosen SHA variant is not supported");k=x(e);this.setHMACKey=function(a,b,c){var d;if(!0===p)throw Error("HMAC key already set");if(!0===u)throw Error("Cannot set HMAC key after calling update"); -f=(c||{}).encoding||"UTF8";b=z(b,f)(a);a=b.binLen;b=b.value;d=m>>>3;c=d/4-1;if(da/8){for(;b.length<=c;)b.push(0);b[c]&=4294967040}for(a=0;a<=c;a+=1)q[a]=b[a]^909522486,t[a]=b[a]^1549556828;k=w(q,k);g=m;p=!0};this.update=function(a){var d,e,f,h=0,n=m>>>5;d=l(a,c,b);a=d.binLen;e=d.value;d=a>>>5;for(f=0;f>>5);b=a%m;u=!0};this.getHash=function(a,d){var f,l,m,r;if(!0=== -p)throw Error("Cannot call getHash after setting HMAC key");m=B(d);switch(a){case "HEX":f=function(a){return C(a,h,m)};break;case "B64":f=function(a){return D(a,h,m)};break;case "BYTES":f=function(a){return E(a,h)};break;case "ARRAYBUFFER":try{l=new ArrayBuffer(0)}catch(I){throw Error("ARRAYBUFFER not supported by this environment");}f=function(a){return F(a,h)};break;default:throw Error("format must be HEX, B64, BYTES, or ARRAYBUFFER");}r=n(c.slice(),b,g,y(k),h);for(l=1;l>>3;if(0!==g%2)throw Error("String of HEX type must be in byte increments");for(c=0;c>>1)+l;for(f=k>>>2;a.length<=f;)a.push(0);a[f]|=b<<8*(3-k%4)}return{value:a,binLen:4*g+d}}function K(e,a,d){var g=[],c,b,f,k,g=a||[0];d=d||0;b=d>>>3;for(c=0;c>>2,g.length<=f&&g.push(0),g[f]|=a<<8*(3-k%4);return{value:g,binLen:8*e.length+d}}function L(e,a,d){var g=[],c=0,b,f,k,l,h,m,g=a||[0];d=d||0;a=d>>>3;if(-1===e.search(/^[a-zA-Z0-9=+\/]+$/))throw Error("Invalid character in base-64 string");f=e.indexOf("=");e=e.replace(/\=/g,"");if(-1!==f&&f - - \ No newline at end of file diff --git a/game/ticketServer/header.php b/game/ticketServer/header.php deleted file mode 100644 index 89eecccd..00000000 --- a/game/ticketServer/header.php +++ /dev/null @@ -1,9 +0,0 @@ - - - -Sleep Is Death (Geisterfahrer) - - - - diff --git a/game/ticketServer/index.php b/game/ticketServer/index.php deleted file mode 100644 index 894c903a..00000000 --- a/game/ticketServer/index.php +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - -
- -
- - - -
- -
- Yubikey:
- - - - - - - -
-
-Server-provided Pepper: -
- - -
-hmac_sha1 of password with pepper as key:
- - -
- - - \ No newline at end of file diff --git a/game/ticketServer/passwordHashUtility.php b/game/ticketServer/passwordHashUtility.php deleted file mode 100644 index 34ff48f0..00000000 --- a/game/ticketServer/passwordHashUtility.php +++ /dev/null @@ -1,28 +0,0 @@ - -
- - - - diff --git a/game/ticketServer/protocol.txt b/game/ticketServer/protocol.txt deleted file mode 100644 index 1f03aa06..00000000 --- a/game/ticketServer/protocol.txt +++ /dev/null @@ -1,153 +0,0 @@ - - -// creates a ticket record and returns a ticket code - -server.php -?action=sell_ticket -&name=[human name] -&email=[email address] -&reference=[order number] -&tags=[ticket_type] -&security_data=[data] -&security_hash=[md5 hash] - -ticket_type can be: - -april_9 -april_12 - - - -// checks if download code is valid - -server.php -?action=check_ticket -&ticket_id=[ID] - -Return: -VALID --or- -INVALID - - - - -// gets email address associated with a download ticket - -server.php -?action=get_ticket_email -&ticket_id=[ID] - -Return: -email --or- -INVALID - - - - -// shows download links - -server.php -?action=show_downloads -&ticket_id=[ID] - - - -// serve a file - -server.php -?action=download -&ticket_id=[ID] -&file_name=[file name] - - - - -// gets a user's download code (encrypted) - -server.php -?action=get_ticket_id -&email=[email address] - - -Returned code is encrypted in the following fashion: - - - substring( toBits( HMAC_SHA1( $sharedEncryptionSecret, $email ) ), LENGTH ) - XOR - toBits( ticket_id ) - - -Where LENGTH is the number of bits in ticket_id. If LENGTH is longer than -160 bits (sha1 length), extra bits are generated and appended via: - - HMAC_SHA1( $sharedEncryptionSecret, - HMAC_SHA1( $sharedEncryptionSecret, $email ) ) - -If more bits are needed, extra bits are generated and appended via: - - HMAC_SHA1( $sharedEncryptionSecret, - HMAC_SHA1( $sharedEncryptionSecret, - HMAC_SHA1( $sharedEncryptionSecret, $email ) ) ) - -And so on. - - -ticket_id values are in "readable base-32", which is base 32 with possibly -confused characters (0/O and 1/I) removed for readability, and hyphens added -to break the string into clusters of 5 digits. - -Numbers 0, ..., 31 are encoded by the following characters: - -"2", "3", "4", "5", "6", "7", "8", "9", -"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", -"N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" - - -toBits simply converts a given encoding (hex or base-32) into binary. - - -and XOR is a bit-wise XOR operation. - - -The resulting bit string is re-encoded in readable base-32, without hyphens - - - -Returns DENIED if email not found or user blocked. - - - - - - -// verifies a hash using a user's secret ticket_id as the key -// this allows remote checking of download codes without sending them accross - -server.php -?action=check_ticket_hash -&email=[email address] -&hash_value=[hash value] -&string_to_hash=[string] - - -Return: -VALID --or- -INVALID - - -string_to_hash must contain only the charcters 0-9, A-Z, and a-z - -hash_value is computed on both ends with: - -HMAC_SHA1( $ticket_id, $string_to_hash ) - - -Where $ticket_id has hyphens removed and is all uppercase. - - -Note that string_to_hash should not be re-used for subsequent checks to avoid -replay attacks. HOWEVER, the ticketServer does NOT track this or prevent -replays. It is up to the other server to handle this. \ No newline at end of file diff --git a/game/ticketServer/server.php b/game/ticketServer/server.php deleted file mode 100644 index 7835c57d..00000000 --- a/game/ticketServer/server.php +++ /dev/null @@ -1,3587 +0,0 @@ - -Ticket Permissions Server Web-based setup - - -
- -
- -
"; - -$setup_footer = " -
-
-
-"; - - - - - - -// ensure that magic quotes are OFF -// we hand-filter all _REQUEST data with regexs before submitting it to the DB -if( get_magic_quotes_gpc() ) { - // force magic quotes to be removed - $_GET = array_map( 'ts_stripslashes_deep', $_GET ); - $_POST = array_map( 'ts_stripslashes_deep', $_POST ); - $_REQUEST = array_map( 'ts_stripslashes_deep', $_REQUEST ); - $_COOKIE = array_map( 'ts_stripslashes_deep', $_COOKIE ); - } - - - -// Check that the referrer header is this page, or kill the connection. -// Used to block XSRF attacks on state-changing functions. -// (To prevent it from being dangerous to surf other sites while you are -// logged in as admin.) -// Thanks Chris Cowan. -function ts_checkReferrer() { - global $fullServerURL; - - if( !isset($_SERVER['HTTP_REFERER']) || - strpos($_SERVER['HTTP_REFERER'], $fullServerURL) !== 0 ) { - - die( "Bad referrer header" ); - } - } - - - - -// all calls need to connect to DB, so do it once here -ts_connectToDatabase(); - -// close connection down below (before function declarations) - - -// testing: -//sleep( 5 ); - - -// general processing whenver server.php is accessed directly - - - - -// grab POST/GET variables -$action = ts_requestFilter( "action", "/[A-Z_]+/i" ); - -$debug = ts_requestFilter( "debug", "/[01]/" ); - -$remoteIP = ""; -if( isset( $_SERVER[ "REMOTE_ADDR" ] ) ) { - $remoteIP = $_SERVER[ "REMOTE_ADDR" ]; - } - - - - -if( $action == "version" ) { - global $ts_version; - echo "$ts_version"; - } -else if( $action == "show_log" ) { - ts_showLog(); - } -else if( $action == "clear_log" ) { - ts_clearLog(); - } -else if( $action == "sell_ticket" ) { - ts_sellTicket(); - } -else if( $action == "block_ticket_id" ) { - ts_blockTicketID(); - } -else if( $action == "delete_ticket_id" ) { - ts_deleteTicketID(); - } -else if( $action == "bulk_email_opt_out" ) { - ts_bulkEmailOptOut(); - } -else if( $action == "check_ticket" ) { - ts_checkTicket(); - } -else if( $action == "get_ticket_email" ) { - ts_getTicketEmail(); - } -else if( $action == "show_downloads" ) { - ts_showDownloads(); - } -else if( $action == "download" ) { - ts_download(); - } -else if( $action == "get_ticket_id" ) { - ts_getTicketID(); - } -else if( $action == "check_ticket_hash" ) { - ts_checkTicketHash(); - } -else if( $action == "show_data" ) { - ts_showData(); - } -else if( $action == "show_detail" ) { - ts_showDetail(); - } -else if( $action == "edit_ticket" ) { - ts_editTicket(); - } -else if( $action == "send_group_email" ) { - ts_sendGroupEmail(); - } -else if( $action == "send_single_email" ) { - ts_sendSingleEmail(); - } -else if( $action == "send_all_note" ) { - ts_sendAllNote(); - } -else if( $action == "add_coupon_codes" ) { - ts_addCouponCodes(); - } -else if( $action == "clear_coupon_codes" ) { - ts_clearCouponCodes(); - } -else if( $action == "send_all_file_note" ) { - ts_sendAllFileNote(); - } -else if( $action == "email_opt_in" ) { - ts_emailOptIn(); - } -else if( $action == "edit_email" ) { - ts_editEmail(); - } -else if( $action == "change_email" ) { - ts_changeEmail(); - } -else if( $action == "logout" ) { - ts_logout(); - } -else if( $action == "ts_setup" ) { - global $setup_header, $setup_footer; - echo $setup_header; - - echo "

Ticket Server Web-based Setup

"; - - echo "Creating tables:
"; - - echo "
-
- -
"; - - ts_setupDatabase(); - - echo "


"; - - echo $setup_footer; - } -else if( preg_match( "/server\.php/", $_SERVER[ "SCRIPT_NAME" ] ) ) { - // server.php has been called without an action parameter - - // the preg_match ensures that server.php was called directly and - // not just included by another script - - // quick (and incomplete) test to see if we should show instructions - global $tableNamePrefix; - - // check if our tables exist - $exists = ts_doesTableExist( $tableNamePrefix . "tickets" ) && - ts_doesTableExist( $tableNamePrefix . "log" ) && - ts_doesTableExist( $tableNamePrefix . "downloads" ); - - - if( $exists ) { - echo "Ticket Server database setup and ready"; - } - else { - // start the setup procedure - - global $setup_header, $setup_footer; - echo $setup_header; - - echo "

Ticket Server Web-based Setup

"; - - echo "Ticket Server will walk you through a " . - "brief setup process.

"; - - echo "Step 1: ". - "
". - "create the database tables"; - - echo $setup_footer; - } - } - - - -// done processing -// only function declarations below - -ts_closeDatabase(); - - - - - - - -/** - * Creates the database tables needed by seedBlogs. - */ -function ts_setupDatabase() { - global $tableNamePrefix; - - $tableName = $tableNamePrefix . "log"; - if( ! ts_doesTableExist( $tableName ) ) { - - // this table contains general info about the server - // use INNODB engine so table can be locked - $query = - "CREATE TABLE $tableName(" . - "entry TEXT NOT NULL, ". - "entry_time DATETIME NOT NULL );"; - - $result = ts_queryDatabase( $query ); - - echo "$tableName table created
"; - } - else { - echo "$tableName table already exists
"; - } - - - - $tableName = $tableNamePrefix . "tickets"; - if( ! ts_doesTableExist( $tableName ) ) { - - // this table contains general info about each ticket - $query = - "CREATE TABLE $tableName(" . - "ticket_id VARCHAR(255) NOT NULL PRIMARY KEY," . - "sale_date DATETIME NOT NULL," . - "last_download_date DATETIME NOT NULL," . - "name TEXT NOT NULL, ". - "email CHAR(255) NOT NULL," . - "order_number CHAR(255) NOT NULL," . - "tag CHAR(255) NOT NULL," . - "coupon_code TEXT NOT NULL," . - "email_sent TINYINT NOT NULL," . - "blocked TINYINT NOT NULL," . - "download_count INT NOT NULL, ". - "email_opt_in TINYINT NOT NULL );"; - - $result = ts_queryDatabase( $query ); - - echo "$tableName table created
"; - } - else { - echo "$tableName table already exists
"; - } - - - - - $tableName = $tableNamePrefix . "downloads"; - if( ! ts_doesTableExist( $tableName ) ) { - - // this table contains information about each download that occurred - $query = - "CREATE TABLE $tableName(" . - "ticket_id VARCHAR(255) NOT NULL," . - "download_date DATETIME NOT NULL," . - "file_name TEXT NOT NULL," . - "blocked TINYINT NOT NULL," . - "ip_address CHAR(255) NOT NULL," . - "PRIMARY KEY( ticket_id, download_date ) );"; - - $result = ts_queryDatabase( $query ); - - echo "$tableName table created
"; - } - else { - echo "$tableName table already exists
"; - } - } - - - -function ts_showLog() { - ts_checkPassword( "show_log" ); - - echo "[Main]


"; - - global $tableNamePrefix; - - $query = "SELECT * FROM $tableNamePrefix"."log ". - "ORDER BY entry_time DESC;"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - - - echo "". - "Clear log"; - - echo "
"; - - echo "$numRows log entries:


\n"; - - - for( $i=0; $i<$numRows; $i++ ) { - $time = ts_mysqli_result( $result, $i, "entry_time" ); - $entry = htmlspecialchars( ts_mysqli_result( $result, $i, "entry" ) ); - - echo "$time:
$entry
\n"; - } - } - - - -function ts_clearLog() { - ts_checkPassword( "clear_log" ); - - echo "[Main]


"; - - global $tableNamePrefix; - - $query = "DELETE FROM $tableNamePrefix"."log;"; - $result = ts_queryDatabase( $query ); - - if( $result ) { - echo "Log cleared."; - } - else { - echo "DELETE operation failed?"; - } - } - - - - - - - -function ts_sellTicket() { - global $tableNamePrefix, $fastspringPrivateKeys, $remoteIP; - global $ticketIDLength, $ticketGenerationSecret, $ts_mysqlLink; - - - $tags = ts_requestFilter( "tags", "/[A-Z0-9_,-]+/i" ); - if( $tags == "" ) { - // no tag set? - // default to first one - $arrayKeys = array_keys( $fastspringPrivateKeys ); - $tags = $arrayKeys[ 0 ]; - } - - $separateTags = preg_split( "/,/", $tags ); - - - $privateKey = ""; - $tag = ""; - - for( $t=0; $tMain]


"; - } - - - - - - - $bulk = ts_requestFilter( "bulk", "/[01]/", "0" ); - - $emailList = array(); - - - if( ! $bulk ) { - - $email = ts_requestFilter( "email", "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i" ); - - $emailList[] = $email; - } - else { - - $emails = ""; - if( isset( $_REQUEST[ "emails" ] ) ) { - $emails = $_REQUEST[ "emails" ]; - } - - $emailList = preg_split( "/\s+/", $emails ); - } - - $failedCount = 0; - $successCount = 0; - - foreach( $emailList as $email ) { - - $unfilteredEmail = $email; - $email = ts_filter( $email, "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i", "" ); - - if( $email == "" ) { - echo "Invalid email address: $unfilteredEmail
"; - $failedCount++; - } - else { - $nameFromEmail = - ts_requestFilter( "name_from_email", "/[01]/", "0" ); - - $name = ""; - - if( ! $nameFromEmail ) { - - $name = ts_requestFilter( "name", "/[A-Z0-9.' -_]+/i" ); - - // some names have ' in them - // need to escape this for use in DB query - $name = mysqli_real_escape_string( $ts_mysqlLink, $name ); - } - else { - $emailParts = preg_split( "/@/", $email ); - - if( count( $emailParts ) == 2 ) { - $name = $emailParts[0]; - } - } - - - - $found_unused_id = 0; - $salt = 0; - - - while( ! $found_unused_id ) { - - - - $ticket_id = ""; - - // repeat hashing new rand values, mixed with our secret - // for security, until we have generated enough digits. - while( strlen( $ticket_id ) < $ticketIDLength ) { - - $randVal = rand(); - - $hash_bin = - ts_hmac_sha1_raw( $ticketGenerationSecret, - $name . uniqid( "$randVal"."$salt", - true ) ); - - - $hash_base32 = ts_readableBase32Encode( $hash_bin ); - - $digitsLeft = $ticketIDLength - strlen( $ticket_id ); - - $ticket_id = $ticket_id . substr( $hash_base32, - 0, $digitsLeft ); - } - - - // break into "-" separated chunks of 5 digits - $ticket_id_chunks = str_split( $ticket_id, 5 ); - - $ticket_id = implode( "-", $ticket_id_chunks ); - - - - /* - "ticket_id VARCHAR(255) NOT NULL PRIMARY KEY," . - "sale_date DATETIME NOT NULL," . - "last_download_date DATETIME NOT NULL," . - "name TEXT NOT NULL, ". - "email CHAR(255) NOT NULL," . - "order_number CHAR(255) NOT NULL," . - "tag CHAR(255) NOT NULL," . - "coupon_code TEXT NOT NULL," . - "email_sent TINYINT NOT NULL," . - "blocked TINYINT NOT NULL," . - "download_count INT, ". - "email_opt_in TINYINT NOT NULL );"; - */ - - - // opt-in to emails by default - $query = "INSERT INTO $tableNamePrefix". "tickets VALUES ( " . - "'$ticket_id', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, ". - "'$name', '$email', '$order_number', ". - "'$tag', '', '0', '0', '0', " . - "'$email_opt_in' );"; - - - $result = mysqli_query( $ts_mysqlLink, $query ); - - if( $result ) { - $found_unused_id = 1; - - ts_log( "Ticket $ticket_id created by $remoteIP" ); - - - if( ! $manual ) { - echo "$ticket_id"; - } - else { - echo "$email
$ticket_id

\n"; - } - $successCount++; - } - else { - global $debug; - if( $debug == 1 ) { - echo "Duplicate ids? Error: " . - mysqli_error( $ts_mysqlLink ) ."
"; - } - // try again - $salt += 1; - } - } - - } - } - - if( $manual ) { - echo "

Summary: $failedCount Failed, ". - "$successCount newly created"; - } - } - - - - - -function ts_getTicketID() { - global $tableNamePrefix, $sharedEncryptionSecret; - - $email = ts_requestFilter( "email", "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i" ); - - $query = "SELECT ticket_id FROM $tableNamePrefix"."tickets ". - "WHERE email = '$email' AND blocked = '0';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - $ticket_id = ""; - - // could be more than one with this email - // return first only - if( $numRows > 0 ) { - $ticket_id = ts_mysqli_result( $result, 0, "ticket_id" ); - } - else { - echo "DENIED"; - return; - } - - - - // remove hyphens - $ticket_id = implode( preg_split( "/-/", $ticket_id ) ); - - $ticket_id_bits = ts_readableBase32DecodeToBitString( $ticket_id ); - - $ticketLengthBits = strlen( $ticket_id_bits ); - - - // generate enough bits by hashing shared secret repeatedly - $hexToMixBits = ""; - - $runningSecret = ts_hmac_sha1( $sharedEncryptionSecret, $email ); - while( strlen( $hexToMixBits ) < $ticketLengthBits ) { - - $newBits = ts_hexDecodeToBitString( $runningSecret ); - - $hexToMixBits = $hexToMixBits . $newBits; - - $runningSecret = ts_hmac_sha1( $sharedEncryptionSecret, - $runningSecret ); - } - - // trim down to bits that we need - $hexToMixBits = substr( $hexToMixBits, 0, $ticketLengthBits ); - - $mixBits = str_split( $hexToMixBits ); - $ticketBits = str_split( $ticket_id_bits ); - - // bitwise xor - $i = 0; - foreach( $mixBits as $bit ) { - if( $bit == "1" ) { - if( $ticket_id_bits[$i] == "1" ) { - - $ticketBits[$i] = "0"; - } - else { - $ticketBits[$i] = "1"; - } - } - $i++; - } - - $ticket_id_bits = implode( $ticketBits ); - - $encrypted_ticket_id = - ts_readableBase32EncodeFromBitString( $ticket_id_bits ); - - echo "$encrypted_ticket_id"; - } - - - -function ts_checkTicketHash() { - global $tableNamePrefix; - - $email = ts_requestFilter( "email", "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i" ); - - if( ! ts_checkForSteamEmail( $email ) ) { - echo "INVALID"; - return; - } - - - $query = "SELECT ticket_id FROM $tableNamePrefix"."tickets ". - "WHERE email = '$email' AND blocked = '0';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - $ticket_id = ""; - - // could be more than one with this email - // return first only - if( $numRows > 0 ) { - $ticket_id = ts_mysqli_result( $result, 0, "ticket_id" ); - } - else { - ts_log( "email $email not found on check_ticket_hash" ); - echo "INVALID"; - return; - } - - // remove hyphens - $ticket_id = implode( preg_split( "/-/", $ticket_id ) ); - - - $hash_value = ts_requestFilter( "hash_value", "/[A-F0-9]+/i", "" ); - - $hash_value = strtoupper( $hash_value ); - - $string_to_hash = - ts_requestFilter( "string_to_hash", "/[A-Z0-9]+/i", "0" ); - - - $computedHashValue = - strtoupper( ts_hmac_sha1( $ticket_id, $string_to_hash ) ); - - - if( $computedHashValue == $hash_value ) { - echo "VALID"; - } - else { - ts_log( "hash for $email invalid on check_ticket_hash" ); - echo "INVALID"; - } - } - - - - -function ts_editTicket() { - - ts_checkPassword( "edit_ticket" ); - global $tableNamePrefix, $remoteIP, $ts_mysqlLink; - - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - - $name = ts_requestFilter( "name", "/[A-Z0-9.' -]+/i" ); - - // some names have ' in them - // need to escape this for use in DB query - $name = mysqli_real_escape_string( $ts_mysqlLink, $name ); - - - $email = ts_requestFilter( "email", "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i" ); - - $order_number = ts_requestFilter( "reference", "/[A-Z0-9-]+/i" ); - - $tag = ts_requestFilter( "tag", "/[A-Z0-9_-]+/i" ); - - $email_opt_in = ts_requestFilter( "email_opt_in", "/[01]/", "1" ); - - - - $query = "UPDATE $tableNamePrefix". "tickets SET " . - "name = '$name', email = '$email', ". - "order_number = '$order_number', tag = '$tag', " . - "email_opt_in = '$email_opt_in' " . - "WHERE ticket_id = '$ticket_id';"; - - global $ts_mysqlLink; - - $result = mysqli_query( $ts_mysqlLink, $query ); - - if( $result ) { - ts_log( "$ticket_id data changed by $remoteIP" ); - echo "Update of $ticket_id succeeded

"; - - // don't check password again here - ts_showDetail( false ); - } - else { - ts_log( "$ticket_id data change failed for $remoteIP" ); - - echo "Update of $ticket_id failed"; - } - } - - - -function ts_blockTicketID() { - ts_checkPassword( "block_ticket_id" ); - - - global $tableNamePrefix; - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - - $blocked = ts_requestFilter( "blocked", "/[01]/", "0" ); - - - global $remoteIP; - - - - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 1 ) { - - - $query = "UPDATE $tableNamePrefix"."tickets SET " . - "blocked = '$blocked' " . - "WHERE ticket_id = '$ticket_id';"; - - $result = ts_queryDatabase( $query ); - - - ts_log( "$ticket_id block changed to $blocked by $remoteIP" ); - - ts_showData(); - } - else { - ts_log( "$ticket_id not found for $remoteIP" ); - - echo "$ticket_id not found"; - } - } - - - -function ts_deleteTicketID() { - ts_checkPassword( "delete_ticket_id" ); - - global $tableNamePrefix, $remoteIP; - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - - $query = "DELETE FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - if( $result ) { - ts_log( "$ticket_id deleted by $remoteIP" ); - - echo "$ticket_id deleted.
"; - - // don't check password again here - ts_showData( false ); - } - else { - ts_log( "$ticket_id delete failed for $remoteIP" ); - - echo "DELETE operation failed?"; - } - } - - - -function ts_bulkEmailOptOut() { - ts_checkPassword( "bulk_email_opt_out" ); - - global $tableNamePrefix, $remoteIP, $ts_mysqlLink; - - // input filtering handled below - $emails = ""; - if( isset( $_REQUEST[ "emails" ] ) ) { - $emails = $_REQUEST[ "emails" ]; - } - - $emailArray = preg_split( "/\s+/", $emails ); - - - $totalCount = count( $emailArray ); - ts_log( "$totalCount opt-out initiated by $remoteIP" ); - - - $failedCount = 0; - $alreadyOutCount = 0; - $successCount = 0; - foreach( $emailArray as $email ) { - $unfilteredEmail = $email; - $email = ts_filter( $email, "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i", "" ); - - if( $email == "" ) { - echo "Invalid email address: $unfilteredEmail
"; - $failedCount++; - } - else { - $email = strtolower( $email ); - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."tickets ". - "WHERE email = '$email';"; - - $result = ts_queryDatabase( $query ); - - $countMatching = ts_mysqli_result( $result, 0, 0 ); - - if( $countMatching > 0 ) { - - - $query = "UPDATE $tableNamePrefix"."tickets ". - "SET email_opt_in=0 WHERE email = '$email';"; - - $result = ts_queryDatabase( $query ); - - $affected = mysqli_affected_rows( $ts_mysqlLink ); - - $successCount += $affected; - - $alreadyOutCount += ( $countMatching - $affected ); - } - else { - echo "Email $email not found
"; - $failedCount++; - } - } - } - - echo "Summary: $failedCount Failed, ". - "$alreadyOutCount already opted-out, ". - "$successCount newly opted out"; - echo "
"; - ts_showData( false ); - } - - - -function ts_downloadAllowed() { - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - global $tableNamePrefix, $remoteIP; - - - global $header, $footer; - - - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 1 ) { - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - $blocked = $row[ "blocked" ]; - - $tag = $row[ "tag" ]; - - $email = $row[ "email" ]; - - if( ! ts_checkForSteamEmail( $email ) ) { - eval( $header ); - echo "You no longer own the game on Steam"; - eval( $footer ); - return 0; - } - - - date_default_timezone_set( "America/New_York" ); - - - $currentTimestamp = time(); - - $allowedTimestamp; - - $downloadReady = 1; - - - global $allowedDownloadDates; - - $allowedTimestamp = strtotime( $allowedDownloadDates[ $tag ] ); - - - - if( $currentTimestamp < $allowedTimestamp ) { - - eval( $header ); - - $allowedDateString = date( "l, F j, Y", $allowedTimestamp ); - echo "Your download will be available on ". - "$allowedDateString (New York Time)
\n"; - - $d = $allowedTimestamp - $currentTimestamp; - - $hours = (int)( $d / 3600 ); - - $seconds = (int)( $d % 3600 ); - $minutes = (int)( $seconds / 60 ); - $seconds = (int)( $seconds % 60 ); - - $days = (int)( $hours / 24 ); - $hours = (int)( $hours % 24 ); - - - echo "(That's in $days days, $hours hours, ". - "$minutes minutes, and $seconds seconds)
\n"; - - $currentDateString = date( "l, F j, Y [g:i a]", - $currentTimestamp ); - - echo "Current New York time: $currentDateString
\n"; - - eval( $footer ); - - $downloadReady = 0; - } - - - - // format as in Sunday, July 7, 2005 [4:52 pm] - //$dateString = date( "l, F j, Y [g:i a]", $timestamp ); - - if( !$blocked ){ - $blocked = !$downloadReady; - } - - if( !$blocked ) { - - ts_log( "$ticket_id permitted to download by $remoteIP" ); - - return 1; - } - else { - - if( $downloadReady ) { - eval( $header ); - echo "Your download access is currently blocked"; - eval( $footer ); - - ts_log( "$ticket_id denied to download by ". - "$remoteIP (blocked)" ); - } - else { - ts_log( "$ticket_id denied to download by ". - "$remoteIP (too early)" ); - } - - return 0; - } - } - eval( $header ); - echo "Your ticket number was not found"; - eval( $footer ); - - ts_log( "$ticket_id denied to download by $remoteIP (not found)" ); - - return 0; - } - - -function ts_printLink( $inFileName, $inTicketID ) { - global $useRemoteMirrors, $remoteMirrorURLFile; - - if( $useRemoteMirrors ) { - - if( is_file( $remoteMirrorURLFile ) ) { - - $urls = file( $remoteMirrorURLFile, - FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES ); - - $num = count( $urls ); - - - if( $num > 0 ) { - - // pick one at random - $url = $urls[ mt_rand( 0, $num - 1 ) ]; - - $url = $url . $inFileName; - - - echo "$inFileName"; - return; - } - } - } - - - // default: server directly through our script - - echo "$inFileName"; - } - - - -function ts_checkTicket() { - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - global $tableNamePrefix; - - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id' AND blocked = 0;"; - $result = ts_queryDatabase( $query ); - - $countMatching = ts_mysqli_result( $result, 0, 0 ); - - if( $countMatching == 1 ) { - echo "VALID"; - } - else { - echo "INVALID"; - } - } - - - -function ts_getTicketEmail() { - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - global $tableNamePrefix; - - - - $query = "SELECT email FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id' AND blocked = 0;"; - $result = ts_queryDatabase( $query ); - - if( mysqli_num_rows( $result ) == 1 ) { - - $email = ts_mysqli_result( $result, 0, 0 ); - - echo $email; - } - else { - echo "INVALID"; - } - } - - - -function ts_showDownloads() { - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - global $tableNamePrefix, $remoteIP; - - - if( ts_downloadAllowed() ) { - global $fileList, $fileDescriptions, $fileListHeader, $footer; - - $coupon_code = ""; - - - $query = "SELECT email, coupon_code from $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - - $result = ts_queryDatabase( $query ); - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - $email = $row[ "email" ]; - $coupon_code = $row[ "coupon_code" ]; - - - - - eval( $fileListHeader ); - - echo "
"; - - for( $i=0; $i"; - $des = $fileDescriptions[$i]; - echo ""; - } - echo "
"; - ts_printLink( $fileList[$i], $ticket_id ); - echo "$des
"; - - - - // show opt in or opt out link? - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 1 ) { - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - $email_opt_in = $row[ "email_opt_in" ]; - - echo "

"; - - if( $email_opt_in == '1' ) { - echo "[Opt Out] of email updates."; - } - else { - echo "[Opt In] to email updates."; - } - - global $canEditEmail; - - if( $canEditEmail ) { - - echo " -- [Change] your email address."; - } - } - - - eval( $footer ); - } - } - - - - -function ts_download() { - global $ts_mysqlLink; - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - $file_name = ts_requestFilter( "file_name", "/[A-Z0-9_.-]+/i" ); - - - global $tableNamePrefix, $remoteIP; - - - - $blocked = ! ts_downloadAllowed(); - - - - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 1 ) { - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - - // catalog blocked runs, too - $download_count = $row[ "download_count" ]; - - $download_count ++; - - - $query = "UPDATE $tableNamePrefix"."tickets SET " . - "last_download_date = CURRENT_TIMESTAMP, " . - "download_count = '$download_count' " . - "WHERE ticket_id = '$ticket_id';"; - - - $result = ts_queryDatabase( $query ); - - - $query = "INSERT INTO $tableNamePrefix". "downloads VALUES ( " . - "'$ticket_id', CURRENT_TIMESTAMP, '$file_name', ". - "'$blocked', '$remoteIP' );"; - - $result = mysqli_query( $ts_mysqlLink, $query ); - - - if( !$blocked ) { - global $downloadFilePath; - - $result = ts_send_file( $downloadFilePath . $file_name ); - - if( ! $result ) { - global $header, $footer; - - eval( $header ); - - echo "File not found."; - - eval( $footer ); - } - - return; - } - else { - return; - } - } - } - - - - -function ts_emailOptIn() { - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - $in = ts_requestFilter( "in", "/[01]/", "1" ); - - - global $tableNamePrefix, $remoteIP; - - - if( ts_downloadAllowed() ) { - global $header, $footer; - - - eval( $header ); - - - $query = "UPDATE $tableNamePrefix"."tickets ". - "SET email_opt_in='$in' WHERE ticket_id = '$ticket_id';"; - - $result = ts_queryDatabase( $query ); - - echo "Email updates for your download ticket are currently "; - - if( $in == 1 ) { - echo "on

\n"; - } - else { - echo "off

\n"; - } - - - // show opt in or opt out link? - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 1 ) { - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - $email_opt_in = $row[ "email_opt_in" ]; - - - - if( $email_opt_in == '1' ) { - echo "[Opt Out] of email updates."; - } - else { - echo "[Opt In] to email updates."; - } - } - - echo "

"; - - echo "[Return] to your download page."; - - eval( $footer ); - } - } - - - -function ts_editEmail() { - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - global $tableNamePrefix, $remoteIP; - - - if( ts_downloadAllowed() ) { - global $header, $footer; - - - global $canEditEmail; - - if( ! $canEditEmail ) { - - eval( $header ); - - echo "Operation disabled."; - - eval( $footer ); - - return; - } - - - - $query = "SELECT email from $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - - $result = ts_queryDatabase( $query ); - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - $email = $row[ "email" ]; - - - eval( $header ); - -?> -

- Edit Email:

- - - - - - -
-
"; - - echo "[Return] to your download page."; - - eval( $footer ); - } - } - - - - -function ts_changeEmail() { - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - $email = ts_requestFilter( "email", "/[A-Z0-9._%+-]+@[A-Z0-9.-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - global $tableNamePrefix; - - - if( ts_downloadAllowed() ) { - - global $canEditEmail; - - if( ! $canEditEmail ) { - global $header, $footer; - - eval( $header ); - - echo "Operation disabled."; - - eval( $footer ); - - return; - } - - - $query = "UPDATE $tableNamePrefix"."tickets ". - "SET email='$email' WHERE ticket_id = '$ticket_id';"; - - $result = ts_queryDatabase( $query ); - - ts_log( "Email changed to $email for ticket $ticket_id" ); - - ts_showDownloads(); - } - } - - - -function ts_logout() { - ts_checkReferrer(); - - ts_clearPasswordCookie(); - - echo "Logged out"; - } - - - - -// if email is a steamID alias, check if the user still owns the app -// returns true on ownership, or if it's a non-steamID email -// returns false for steamID emails that do not own the game -function ts_checkForSteamEmail( $inEmail ) { - $matched = preg_match( "#(\d+)@steamgames.com#", $inEmail, $matches ); - - if( $matched ) { - $resultID = ts_doesSteamUserOwnApp( $matches[1] ); - - if( $resultID == $matches[1] ) { - return true; - } - return false; - } - else { - // non-steam email - return true; - } - } - - - -// Checks ownership of $steamAppID (from settings.php) -// returns the steamID of the true owner if they have access to it (may be -// ID of family member) -// returns 0 if they don't own it at all. -function ts_doesSteamUserOwnApp( $inSteamID ) { - global $steamAppID, $steamWebAPIKey; - - $url = "https://partner.steam-api.com/ISteamUser/CheckAppOwnership/V0001". - "?format=xml". - "&key=$steamWebAPIKey". - "&steamid=$inSteamID". - "&appid=$steamAppID"; - - $result = file_get_contents( $url ); - - - $matched = preg_match( "#(\w+)#", - $result, $matches ); - - if( $matched && $matches[1] == "true" ) { - - // make sure we return the true owner - $matchedB = preg_match( "#(\d+)#", - $result, $matchesB ); - - if( $matchedB ) { - return $matchesB[1]; - } - else { - return 0; - } - } - else { - return 0; - } - } - - - - -function ts_showData( $checkPassword = true ) { - // these are global so they work in embeded function call below - global $skip, $search, $order_by; - - if( $checkPassword ) { - ts_checkPassword( "show_data" ); - } - - global $tableNamePrefix, $remoteIP; - - - echo "". - "". - "". - "
[Main][Logout]



"; - - - - - $skip = ts_requestFilter( "skip", "/[0-9]+/", 0 ); - - global $ticketsPerPage; - - $search = ts_requestFilter( "search", "/[A-Z0-9_@. -]+/i" ); - - $order_by = ts_requestFilter( "order_by", "/[A-Z_]+/i", - "last_download_date" ); - - $keywordClause = ""; - $searchDisplay = ""; - - if( $search != "" ) { - - - $keywordClause = "WHERE ( name LIKE '%$search%' " . - "OR email LIKE '%$search%' ". - "OR ticket_id LIKE '%$search%' ". - "OR coupon_code LIKE '%$search%' ". - "OR order_number LIKE '%$search%' ". - "OR tag LIKE '%$search%' ) "; - - $searchDisplay = " matching $search"; - } - - - - - // first, count results - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."tickets $keywordClause;"; - - $result = ts_queryDatabase( $query ); - $totalTickets = ts_mysqli_result( $result, 0, 0 ); - - - $orderDir = "DESC"; - - if( $order_by == "name" || $order_by == "email" ) { - $orderDir = "ASC"; - } - - - $query = "SELECT * FROM $tableNamePrefix"."tickets $keywordClause". - "ORDER BY $order_by $orderDir ". - "LIMIT $skip, $ticketsPerPage;"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - $startSkip = $skip + 1; - - $endSkip = $startSkip + $ticketsPerPage - 1; - - if( $endSkip > $totalTickets ) { - $endSkip = $totalTickets; - } - - - - // form for searching tickets -?> -
-
- - - - -
-
-\n"; - - - $nextSkip = $skip + $ticketsPerPage; - - $prevSkip = $skip - $ticketsPerPage; - - if( $prevSkip >= 0 ) { - echo "[". - "Previous Page] "; - } - if( $nextSkip < $totalTickets ) { - echo "[". - "Next Page]"; - } - - echo "

"; - - echo "\n"; - - function orderLink( $inOrderBy, $inLinkText ) { - global $skip, $search, $order_by; - if( $inOrderBy == $order_by ) { - // already displaying this order, don't show link - return "$inLinkText"; - } - - // else show a link to switch to this order - return "$inLinkText"; - } - - - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - - - for( $i=0; $i<$numRows; $i++ ) { - $ticket_id = ts_mysqli_result( $result, $i, "ticket_id" ); - $sale_date = ts_mysqli_result( $result, $i, "sale_date" ); - $lastDL = ts_mysqli_result( $result, $i, "last_download_date" ); - $count = ts_mysqli_result( $result, $i, "download_count" ); - $name = ts_mysqli_result( $result, $i, "name" ); - $email = ts_mysqli_result( $result, $i, "email" ); - $tag = ts_mysqli_result( $result, $i, "tag" ); - $coupon_code = ts_mysqli_result( $result, $i, "coupon_code" ); - $blocked = ts_mysqli_result( $result, $i, "blocked" ); - $sent = ts_mysqli_result( $result, $i, "email_sent" ); - - $block_toggle = ""; - - if( $blocked ) { - $blocked = "BLOCKED"; - $block_toggle = "unblock"; - - } - else { - $blocked = ""; - $block_toggle = "block"; - - } - - $sent_toggle = ""; - - if( $sent ) { - $sent_toggle = "X"; - } - - - - echo "\n"; - - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo " "; - echo ""; - echo ""; - echo ""; - - echo "\n"; - } - echo "
Ticket ID".orderLink( "name", "Name" )."".orderLink( "email", "Email" )."Sent?Blocked?Coupon".orderLink( "sale_date", "Created" )."Test".orderLink( "last_download_date", "Last DL" )."".orderLink( "download_count", "DL Count" )."
$ticket_id ($tag) "; - echo "[detail]$name$email$sent_toggle$blocked [$block_toggle]$coupon_code$sale_date[run test]$lastDL$count DLs
"; - - - echo "
"; - - // put forms in a table - echo "
\n"; - - - - // fake a security hashes to include in form - global $fastspringPrivateKeys; - - $data = "abc"; - - - // form for force-creating a new id -?> - - - - - - - -
- Create new Ticket:
-
- - - - Email: -
- Name: -
- Order #: -
- Tag: -
- Fake security hash: -
- - - Force email opt-out
- - -
-
- Create Multiple Tickets:
-
- - - - - - - Emails (one per line):
-
- Order #: -
- Tag: -
- Fake security hash: -
- - - Force email opt-out
- - -
-
- Send download emails:
-
- - Tag: -
- Batch size:
-
- Order number filter:
-
- Confirm
- -
-
- Mass email opt-out:

-
- - Emails (one per line):
-
- -
-
\n"; - - - - echo "
"; - - // blank form - ts_printSendAllNoteForm( "", "" ); -?> -
- - - -
- - Subject: -
- File Downloaded: -
- Message:
-
- Confirm
- -
- - - -
- - - - -
- - Add coupon codes:
- (One per line, - each user that does not already have a coupon code gets one.)
- -
- Confirm
- -
-
- - - -
- - Remove coupon codes matching prefix: -
- Confirm
- -
-
- - -". - "Show log"; - echo "
"; - echo "Generated for $remoteIP\n"; - - } - - - -function ts_showDetail( $checkPassword = true ) { - if( $checkPassword ) { - ts_checkPassword( "show_detail" ); - } - - echo "[Main]


"; - - global $tableNamePrefix; - - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - - // form for sending out download emails -?> -
- Send download email:
-
- - - Confirm
- -
-
- -
- Edit ticket:
-
- - - Email: -
- Name: -
- Order #: -
- Tag: -
- > - Email opt-out
- -
-
-DELETE this id]"; - - echo "


\n"; - - - for( $i=0; $i<$numRows; $i++ ) { - $date = ts_mysqli_result( $result, $i, "download_date" ); - $ipAddress = ts_mysqli_result( $result, $i, "ip_address" ); - $file_name = ts_mysqli_result( $result, $i, "file_name" ); - - $blocked = ts_mysqli_result( $result, $i, "blocked" ); - - if( $blocked ) { - $blocked = "BLOCKED"; - } - else { - $blocked = ""; - } - - echo "$date: $ipAddress ($file_name) $blocked
\n"; - } - } - - - -function ts_sendGroupEmail() { - ts_checkPassword( "send_group_email" ); - - - echo "[Main]


"; - - global $tableNamePrefix; - - $confirm = ts_requestFilter( "confirm", "/[01]/" ); - - - - $batch_size = ts_requestFilter( "batch_size", "/[0-9]+/", 0 ); - - - $tag = ts_requestFilter( "tag", "/[A-Z0-9_-]+/i" ); - - $batchClause = ""; - if( $batch_size > 0 ) { - $batchClause = " LIMIT 0, $batch_size "; - } - - - $order_number_filter = ts_requestFilter( "order_number_filter", - "/[A-Z0-9-]+/i", "" ); - - $orderFilterClause = ""; - - if( $order_number_filter != "" ) { - $orderFilterClause = "AND order_number LIKE '%$order_number_filter%'"; - } - - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE tag = '$tag' AND email_sent = '0' AND blocked = '0' ". - " $orderFilterClause ". - "ORDER BY sale_date ASC $batchClause;"; - - - if( $confirm != 1 ) { - echo "You must check the Confirm box to send emails

"; - - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - echo "Would have sent emails to these $numRows people:

"; - - echo "\n"; - - for( $i=0; $i<$numRows; $i++ ) { - $email = ts_mysqli_result( $result, $i, "email" ); - $tag = ts_mysqli_result( $result, $i, "tag" ); - $order_number = ts_mysqli_result( $result, $i, "order_number" ); - - echo - "\n"; - } - echo "
$email$order_number$tag
\n"; - - return; - } - - - - ts_sendEmail_q( $query ); - } - - - -function ts_sendSingleEmail() { - ts_checkPassword( "send_group_email" ); - - - echo "[Main]


"; - - global $tableNamePrefix; - - $confirm = ts_requestFilter( "confirm", "/[01]/" ); - - if( $confirm != 1 ) { - echo "You must check the Confirm box to send emails\n"; - return; - } - - $ticket_id = ts_requestFilter( "ticket_id", "/[A-HJ-NP-Z2-9\-]+/i" ); - - $ticket_id = strtoupper( $ticket_id ); - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - ts_sendEmail_q( $query ); - } - - - -// sends download emails for every result in a SQL query -function ts_sendEmail_q( $inQuery ) { - global $tableNamePrefix; - - $result = ts_queryDatabase( $inQuery ); - - $numRows = mysqli_num_rows( $result ); - - echo "Based on query, sending $numRows emails:


\n"; - - for( $i=0; $i<$numRows; $i++ ) { - $ticket_id = ts_mysqli_result( $result, $i, "ticket_id" ); - $name = ts_mysqli_result( $result, $i, "name" ); - $email = ts_mysqli_result( $result, $i, "email" ); - - echo "[$i] Sending email to $email for ticket $ticket_id ... "; - - $emailResult = ts_sendEmail_p( $ticket_id, $name, $email ); - - if( $emailResult ) { - echo "SUCCESS"; - - $queryB = "UPDATE $tableNamePrefix"."tickets SET " . - "email_sent = '1' " . - "WHERE ticket_id = '$ticket_id';"; - - $resultB = ts_queryDatabase( $queryB ); - } - else { - echo "FAILURE"; - } - echo "

\n"; - flush(); - } - } - - - -// sends a download email for a ticket -function ts_sendEmail( $inTickeID ) { - - global $tableNamePrefix; - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE ticket_id = '$ticket_id';"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - if( $numRows == 1 ) { - - $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ); - - $email = $row[ "email" ]; - $name = $row[ "name" ]; - - return ts_sendEmail_p( $inTickeID, $name, $email ); - } - return 0; - } - - - -// sends a download email for a ticket -function ts_sendEmail_p( $inTickeID, $inName, $inEmail ) { - - - global $siteName, $fullServerURL, $mainSiteURL, - $extraEmailMessage; - - $downloadURL = $fullServerURL. - "?action=show_downloads&ticket_id=$inTickeID"; - - $mailSubject = "Your [$siteName] download is ready"; - - $mailBody = "$inName:\n\n". - "$extraEmailMessage". - "Your can now access your download at:\n\n". - " $downloadURL\n\n". - "You can also access your download manually by ". - "entering your ticket $inTickeID here:\n\n". - " $mainSiteURL\n\n"; - - - /* - echo "\n
Sending mail to: $inEmail
\n"; - echo "Subject: $mailSubject
\n"; - echo "Headers: $mailHeaders
\n"; - echo "Body:
\n
$mailBody

\n"; - */ - - $result = ts_mail( $inEmail, - $mailSubject, - $mailBody, - // download code emails are transactional - true ); - return $result; - } - - -function ts_printSendAllNoteForm( $inSetMessageSubject, $inSetMessageBody ) { - global $tableNamePrefix; -?> -
- - Subject: -
- Tag: - Skip:
- Message:
- (#DOWNLOAD_LINK# will be replaced with individual links)
- (#DOWNLOAD_CODE# will be replaced with individual DL codes)
- (#COUPON_CODE# will be replaced with individual coupon codes)
-
- Confirm
- -
-
-Main]


"; - - global $tableNamePrefix; - - $confirm = ts_requestFilter( "confirm", "/[01]/" ); - - if( $confirm != 1 ) { - echo "You must check the Confirm box to send emails\n"; - return; - } - - - // pass subject and body through without regex filter - // these are put into emails and not put in the database - $message_subject = ""; - if( isset( $_REQUEST[ "message_subject" ] ) ) { - $message_subject = $_REQUEST[ "message_subject" ]; - } - - - $message_text = ""; - if( isset( $_REQUEST[ "message_text" ] ) ) { - $message_text = $_REQUEST[ "message_text" ]; - } - - - $tag = ts_requestFilter( "tag", "/[A-Z0-9_-]+/i" ); - - - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE tag = '$tag' AND blocked = '0' AND email_opt_in = '1' ". - "ORDER BY sale_date ASC;"; - - - $tagParts = preg_split( "/_/", $tag ); - - $useBulk = 0; - - if( count( $tagParts ) == 3 ) { - - if( ( $tagParts[0] == "ALL" || $tagParts[0] == "BULK" ) && - $tagParts[1] == "BATCH" ) { - - // Only send one batch now, according to tag - $numToSkip = $tagParts[2]; - - $message_skip = ts_requestFilter( "message_skip", "/[0-9]+/i", 0 ); - $numToSkip += $message_skip; - - global $emailMaxBatchSize; - - $batchSize = $emailMaxBatchSize; - - if( $tagParts[0] == "BULK" ) { - global $bulkEmailBatchSize; - $batchSize = $bulkEmailBatchSize; - $useBulk = 1; - } - - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE blocked = '0' AND email_opt_in = '1' ". - "ORDER BY sale_date ASC LIMIT $numToSkip, $batchSize;"; - } - } - - - // show opt-out URL at bottom of email - ts_sendNote_q( $query, $message_subject, $message_text, 1, $useBulk ); - - - // show resend form - echo "
"; - - echo "

Done sending for tag $tag.
"; - echo "Send another batch?

"; - - ts_printSendAllNoteForm( $message_subject, $message_text ); - - } - - - -function ts_sendAllFileNote() { - ts_checkPassword( "send_all_note" ); - - - echo "[Main]


"; - - global $tableNamePrefix; - - $confirm = ts_requestFilter( "confirm", "/[01]/" ); - - if( $confirm != 1 ) { - echo "You must check the Confirm box to send emails\n"; - return; - } - - - // don't regex filter subject and body (destined for emails, not DB) - $message_subject = ""; - if( isset( $_REQUEST[ "message_subject" ] ) ) { - $message_subject = $_REQUEST[ "message_subject" ]; - } - - - $message_text = ""; - if( isset( $_REQUEST[ "message_text" ] ) ) { - $message_text = $_REQUEST[ "message_text" ]; - } - - - - $file_name = ts_requestFilter( "file_name", "/[A-Z0-9_.-]+/i" ); - - - $query = "SELECT DISTINCT email, name, ". - "$tableNamePrefix"."tickets.ticket_id, ". - "$tableNamePrefix"."tickets.coupon_code ". - "FROM $tableNamePrefix"."downloads ". - "LEFT JOIN $tableNamePrefix"."tickets ON ". - "$tableNamePrefix"."downloads.ticket_id = ". - "$tableNamePrefix"."tickets.ticket_id ". - "WHERE file_name='$file_name';"; -/* - $query = "SELECT * FROM $tableNamePrefix"."tickets ". - "WHERE tag = '$tag' AND blocked = '0' AND email_opt_in = '1';"; -*/ - ts_sendNote_q( $query, $message_subject, $message_text, 0, 0 ); - } - - - - -function ts_addCouponCodes() { - ts_checkPassword( "add_coupon_codes" ); - - - echo "[Main]


"; - - global $tableNamePrefix; - - $confirm = ts_requestFilter( "confirm", "/[01]/" ); - - if( $confirm != 1 ) { - echo "You must check the Confirm box to add coupons\n"; - return; - } - - - $coupon_codes = ts_requestFilter( "coupon_codes", "/[A-Z0-9 \n\r]+/" ); - - - - $separateCodes = preg_split( "/\s+/", $coupon_codes ); - - - $numCodes = count( $separateCodes ); - - echo "Adding $numCodes new coupon codes...
\n"; - - - $query = "SELECT ticket_id, email FROM $tableNamePrefix"."tickets ". - "WHERE coupon_code = '' LIMIT $numCodes;"; - - - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - - if( $numRows < $numCodes ) { - echo "Warning: ". - "More coupon codes than users still needing a code.
\n"; - } - - - echo "\n"; - - $j = 0; - - - for( $i=0; $i<$numRows && $j<$numCodes; $i++ ) { - $ticket_id = ts_mysqli_result( $result, $i, "ticket_id" ); - $email = ts_mysqli_result( $result, $i, "email" ); - - $coupon_code = $separateCodes[ $j ]; - - $unused = false; - - while( ! $unused ) { - - $query = "SELECT COUNT(*) FROM $tableNamePrefix"."tickets " . - "WHERE coupon_code = '$coupon_code';"; - $countResult = ts_queryDatabase( $query ); - - $alreadyUsingCount = ts_mysqli_result( $countResult, 0, 0 ); - - if( $alreadyUsingCount == 0 ) { - $unused = true; - } - else { - // try next one - - echo "WARNING: ". - "Coupon $coupon_code already ". - "used in database.
\n"; - - $j ++; - if( $j >= $numCodes ) { - break; - } - - $coupon_code = $separateCodes[ $j ]; - } - } - - if( $j >= $numCodes ) { - break; - } - - echo "Setting coupon $coupon_code ". - "for ticket [$ticket_id] ($email)
\n"; - - - - $query = "UPDATE $tableNamePrefix"."tickets SET " . - "coupon_code = '$coupon_code' " . - "WHERE ticket_id = '$ticket_id';"; - ts_queryDatabase( $query ); - - $j++; - } - echo "
\n"; - - echo "Done.
"; - } - - - - - - -function ts_clearCouponCodes() { - ts_checkPassword( "clear_coupon_codes" ); - - - echo "[Main]


"; - - global $tableNamePrefix; - - $confirm = ts_requestFilter( "confirm", "/[01]/" ); - - if( $confirm != 1 ) { - echo "You must check the Confirm box to clear coupons\n"; - return; - } - - - $coupon_prefix = ts_requestFilter( "coupon_prefix", "/[A-Z0-9]+/" ); - - - $query = "UPDATE $tableNamePrefix"."tickets ". - "SET coupon_code = '' ". - "WHERE coupon_code LIKE '$coupon_prefix%';"; - - $result = ts_queryDatabase( $query ); - - global $ts_mysqlLink; - - $affected = mysqli_affected_rows( $ts_mysqlLink ); - - echo "Cleared $affected coupon codes.
\n"; - } - - - - - -// sends note emails for every result in a SQL query -function ts_sendNote_q( $inQuery, $message_subject, $message_text, - $inShowOptOutLink, $inUseBulkEmailer ) { - global $tableNamePrefix, $fullServerURL; - - $result = ts_queryDatabase( $inQuery ); - - $numRows = mysqli_num_rows( $result ); - - echo "Query is:
$inQuery

"; - - echo "Based on query, sending $numRows emails:


\n"; - - if( $inUseBulkEmailer ) { - echo "Using bulk emailer

"; - - $allEmails = array(); - $allCodes = array(); - $allCoupons = array(); - - - $custom_message_text = $message_text; - - if( $inShowOptOutLink ) { - $custom_message_text = $message_text . - "\n\n" . - "-----\n" . - "You can opt out of future email updates by clicking the " . - "following link:\n" . - " $fullServerURL?action=email_opt_in&in=0&" . - "ticket_id=%CUSTOM%" . - "\n\n"; - } - - $custom_link = "$fullServerURL?action=show_downloads&" . - "ticket_id=%CUSTOM%"; - - $custom_message_text = - preg_replace( '/#DOWNLOAD_LINK#/', $custom_link, - $custom_message_text ); - - $custom_message_text = - preg_replace( '/#DOWNLOAD_CODE#/', "%CUSTOM%", - $custom_message_text ); - - $custom_message_text = - preg_replace( '/#COUPON_CODE#/', "%CUSTOM2%", - $custom_message_text ); - - for( $i=0; $i<$numRows; $i++ ) { - $allEmails[] = ts_mysqli_result( $result, $i, "email" ); - $allCodes[] = ts_mysqli_result( $result, $i, "ticket_id" ); - $allCoupons[] = ts_mysqli_result( $result, $i, "coupon_code" ); - } - - - be_addMessage( $message_subject, $custom_message_text, - $allEmails, $allCodes, $allCoupons ); - - - $numAdded = count( $allEmails ); - - echo "Added $numAdded messages to bulk emailer.

"; - return; - } - - - for( $i=0; $i<$numRows; $i++ ) { - $name = ts_mysqli_result( $result, $i, "name" ); - $email = ts_mysqli_result( $result, $i, "email" ); - $ticket_id = ts_mysqli_result( $result, $i, "ticket_id" ); - $coupon_code = ts_mysqli_result( $result, $i, "coupon_code" ); - - echo "[$i] Sending note to $email ... "; - - $custom_message_text = $message_text; - - if( $inShowOptOutLink ) { - $custom_message_text = $message_text . - "\n\n" . - "-----\n" . - "You can opt out of future email updates by clicking the " . - "following link:\n" . - " $fullServerURL?action=email_opt_in&in=0&" . - "ticket_id=$ticket_id" . - "\n\n"; - } - $custom_link = "$fullServerURL?action=show_downloads&" . - "ticket_id=$ticket_id"; - - $custom_message_text = - preg_replace( '/#DOWNLOAD_LINK#/', $custom_link, - $custom_message_text ); - - $custom_message_text = - preg_replace( '/#DOWNLOAD_CODE#/', $ticket_id, - $custom_message_text ); - - $custom_message_text = - preg_replace( '/#COUPON_CODE#/', $coupon_code, - $custom_message_text ); - - $emailResult = ts_sendNote_p( $message_subject, $custom_message_text, - $name, $email ); - - if( $emailResult ) { - echo "SUCCESS"; - } - else { - echo "FAILURE"; - } - echo "

\n"; - flush(); - } - } - - -// sends a note email to a specific name address -function ts_sendNote_p( $message_subject, $message_text, $inName, $inEmail ) { - - - global $siteName, $fullServerURL, $mainSiteURL; - - $mailSubject = $message_subject; - - $mailBody = "$inName:\n\n". $message_text ."\n\n"; - - - /* - echo "\n
Sending mail to: $inEmail
\n"; - echo "Subject: $mailSubject
\n"; - echo "Headers: $mailHeaders
\n"; - echo "Body:
\n
$mailBody

\n"; - */ - - $result = ts_mail( $inEmail, - $mailSubject, - $mailBody, - // note emails are bulk, not transactional - false ); - return $result; - } - - - -function ts_mail( $inEmail, - $inSubject, - $inBody, - // true for transactional emails that should use - // a different SMTP - $inTrans = false ) { - - global $useSMTP, $siteEmailAddress, $siteEmailDomain; - - if( $useSMTP ) { - require_once "Mail.php"; - - global $smtpHost, $smtpPort, $smtpUsername, $smtpPassword; - - $messageID = "<" . uniqid() . "@$siteEmailDomain>"; - - $headers = array( 'From' => $siteEmailAddress, - 'To' => $inEmail, - 'Subject' => $inSubject, - 'Date' => date( "r" ), - 'Message-Id' => $messageID ); - $smtp; - - if( $inTrans ) { - global $smtpHostTrans, $smtpPortTrans, - $smtpUsernameTrans, $smtpPasswordTrans; - - $smtp = Mail::factory( 'smtp', - array ( 'host' => $smtpHostTrans, - 'port' => $smtpPortTrans, - 'auth' => true, - 'username' => $smtpUsernameTrans, - 'password' => $smtpPasswordTrans ) ); - } - else { - $smtp = Mail::factory( 'smtp', - array ( 'host' => $smtpHost, - 'port' => $smtpPort, - 'auth' => true, - 'username' => $smtpUsername, - 'password' => $smtpPassword ) ); - } - - - $mail = $smtp->send( $inEmail, $headers, $inBody ); - - - if( PEAR::isError( $mail ) ) { - ts_log( "Email send failed: " . - $mail->getMessage() ); - return false; - } - else { - return true; - } - } - else { - // raw sendmail - $mailHeaders = "From: $siteEmailAddress"; - - return mail( $inEmail, - $inSubject, - $inBody, - $mailHeaders ); - } - } - - - - -$ts_mysqlLink; - - -// general-purpose functions down here, many copied from seedBlogs - -/** - * Connects to the database according to the database variables. - */ -function ts_connectToDatabase() { - global $databaseServer, - $databaseUsername, $databasePassword, $databaseName, - $ts_mysqlLink; - - - $ts_mysqlLink = - mysqli_connect( $databaseServer, $databaseUsername, $databasePassword ) - or ts_operationError( "Could not connect to database server: " . - mysqli_error( $ts_mysqlLink ) ); - - mysqli_select_db( $ts_mysqlLink, $databaseName ) - or ts_operationError( "Could not select $databaseName database: " . - mysqli_error( $ts_mysqlLink ) ); - } - - - -/** - * Closes the database connection. - */ -function ts_closeDatabase() { - global $ts_mysqlLink; - - mysqli_close( $ts_mysqlLink ); - } - - - -/** - * Queries the database, and dies with an error message on failure. - * - * @param $inQueryString the SQL query string. - * - * @return a result handle that can be passed to other mysql functions. - */ -function ts_queryDatabase( $inQueryString ) { - global $ts_mysqlLink; - - if( gettype( $ts_mysqlLink ) != "resource" ) { - // not a valid mysql link? - ts_connectToDatabase(); - } - - $result = mysqli_query( $ts_mysqlLink, $inQueryString ); - - if( $result == FALSE ) { - - $errorNumber = mysqli_errno( $ts_mysqlLink ); - - // server lost or gone? - if( $errorNumber == 2006 || - $errorNumber == 2013 || - // access denied? - $errorNumber == 1044 || - $errorNumber == 1045 || - // no db selected? - $errorNumber == 1046 ) { - - // connect again? - ts_closeDatabase(); - ts_connectToDatabase(); - - $result = mysqli_query( $ts_mysqlLink, $inQueryString ) - or ts_operationError( - "Database query failed:
$inQueryString

" . - mysqli_error( $ts_mysqlLink ) ); - } - else { - // some other error (we're still connected, so we can - // add log messages to database - ts_fatalError( "Database query failed:
$inQueryString

" . - mysqli_error( $ts_mysqlLink ) ); - } - } - - return $result; - } - - -/** - * Replacement for the old mysql_result function. - */ -function ts_mysqli_result( $result, $number, $field=0 ) { - mysqli_data_seek( $result, $number ); - $row = mysqli_fetch_array( $result ); - return $row[ $field ]; - } - - - -/** - * Checks whether a table exists in the currently-connected database. - * - * @param $inTableName the name of the table to look for. - * - * @return 1 if the table exists, or 0 if not. - */ -function ts_doesTableExist( $inTableName ) { - // check if our table exists - $tableExists = 0; - - $query = "SHOW TABLES"; - $result = ts_queryDatabase( $query ); - - $numRows = mysqli_num_rows( $result ); - - - for( $i=0; $i<$numRows && ! $tableExists; $i++ ) { - - $tableName = ts_mysqli_result( $result, $i, 0 ); - - if( $tableName == $inTableName ) { - $tableExists = 1; - } - } - return $tableExists; - } - - - -function ts_log( $message ) { - global $enableLog, $tableNamePrefix, $ts_mysqlLink; - - if( $enableLog ) { - $slashedMessage = mysqli_real_escape_string( $ts_mysqlLink, $message ); - - $query = "INSERT INTO $tableNamePrefix"."log VALUES ( " . - "'$slashedMessage', CURRENT_TIMESTAMP );"; - $result = ts_queryDatabase( $query ); - } - } - - - -/** - * Displays the error page and dies. - * - * @param $message the error message to display on the error page. - */ -function ts_fatalError( $message ) { - //global $errorMessage; - - // set the variable that is displayed inside error.php - //$errorMessage = $message; - - //include_once( "error.php" ); - - // for now, just print error message - $logMessage = "Fatal error: $message"; - - echo( $logMessage ); - - ts_log( $logMessage ); - - die(); - } - - - -/** - * Displays the operation error message and dies. - * - * @param $message the error message to display. - */ -function ts_operationError( $message ) { - - // for now, just print error message - echo( "ERROR: $message" ); - die(); - } - - -/** - * Recursively applies the addslashes function to arrays of arrays. - * This effectively forces magic_quote escaping behavior, eliminating - * a slew of possible database security issues. - * - * @inValue the value or array to addslashes to. - * - * @return the value or array with slashes added. - */ -function ts_addslashes_deep( $inValue ) { - return - ( is_array( $inValue ) - ? array_map( 'ts_addslashes_deep', $inValue ) - : addslashes( $inValue ) ); - } - - - -/** - * Recursively applies the stripslashes function to arrays of arrays. - * This effectively disables magic_quote escaping behavior. - * - * @inValue the value or array to stripslashes from. - * - * @return the value or array with slashes removed. - */ -function ts_stripslashes_deep( $inValue ) { - return - ( is_array( $inValue ) - ? array_map( 'ts_stripslashes_deep', $inValue ) - : stripslashes( $inValue ) ); - } - - - -/** - * Filters a $_REQUEST variable using a regex match. - * - * Returns "" (or specified default value) if there is no match. - */ -function ts_requestFilter( $inRequestVariable, $inRegex, $inDefault = "" ) { - if( ! isset( $_REQUEST[ $inRequestVariable ] ) ) { - return $inDefault; - } - - return ts_filter( $_REQUEST[ $inRequestVariable ], $inRegex, $inDefault ); - } - - -/** - * Filters a value using a regex match. - * - * Returns "" (or specified default value) if there is no match. - */ -function ts_filter( $inValue, $inRegex, $inDefault = "" ) { - - $numMatches = preg_match( $inRegex, - $inValue, $matches ); - - if( $numMatches != 1 ) { - return $inDefault; - } - - return $matches[0]; - } - - - -// this function checks the password directly from a request variable -// or via hash from a cookie. -// -// It then sets a new cookie for the next request. -// -// This avoids storing the password itself in the cookie, so a stale cookie -// (cached by a browser) can't be used to figure out the password and log in -// later. -function ts_checkPassword( $inFunctionName ) { - $password = ""; - $password_hash = ""; - - $badCookie = false; - - - global $accessPasswords, $tableNamePrefix, $remoteIP, $enableYubikey, - $passwordHashingPepper; - - $cookieName = $tableNamePrefix . "cookie_password_hash"; - - $passwordSent = false; - - if( isset( $_REQUEST[ "passwordHMAC" ] ) ) { - $passwordSent = true; - - // already hashed client-side on login form - // hash again, because hash client sends us is not stored in - // our settings file - $password = ts_hmac_sha1( $passwordHashingPepper, - $_REQUEST[ "passwordHMAC" ] ); - - - // generate a new hash cookie from this password - $newSalt = time(); - $newHash = md5( $newSalt . $password ); - - $password_hash = $newSalt . "_" . $newHash; - } - else if( isset( $_COOKIE[ $cookieName ] ) ) { - ts_checkReferrer(); - $password_hash = $_COOKIE[ $cookieName ]; - - // check that it's a good hash - - $hashParts = preg_split( "/_/", $password_hash ); - - // default, to show in log message on failure - // gets replaced if cookie contains a good hash - $password = "(bad cookie: $password_hash)"; - - $badCookie = true; - - if( count( $hashParts ) == 2 ) { - - $salt = $hashParts[0]; - $hash = $hashParts[1]; - - foreach( $accessPasswords as $truePassword ) { - $trueHash = md5( $salt . $truePassword ); - - if( $trueHash == $hash ) { - $password = $truePassword; - $badCookie = false; - } - } - - } - } - else { - // no request variable, no cookie - // cookie probably expired - $badCookie = true; - $password_hash = "(no cookie. expired?)"; - } - - - - if( ! in_array( $password, $accessPasswords ) ) { - - if( ! $badCookie ) { - - echo "Incorrect password."; - - ts_log( "Failed $inFunctionName access with password: ". - "$password" ); - } - else { - echo "Session expired."; - - ts_log( "Failed $inFunctionName access with bad cookie: ". - "$password_hash" ); - } - - die(); - } - else { - - if( $passwordSent && $enableYubikey ) { - global $yubikeyIDs, $yubicoClientID, $yubicoSecretKey, - $ticketGenerationSecret; - - $yubikey = $_REQUEST[ "yubikey" ]; - - $index = array_search( $password, $accessPasswords ); - $yubikeyIDList = preg_split( "/:/", $yubikeyIDs[ $index ] ); - - $providedID = substr( $yubikey, 0, 12 ); - - if( ! in_array( $providedID, $yubikeyIDList ) ) { - echo "Provided Yubikey does not match ID for this password."; - die(); - } - - - $nonce = ts_hmac_sha1( $ticketGenerationSecret, uniqid() ); - - $callURL = - "https://api2.yubico.com/wsapi/2.0/verify?id=$yubicoClientID". - "&otp=$yubikey&nonce=$nonce"; - - $result = trim( file_get_contents( $callURL ) ); - - $resultLines = preg_split( "/\s+/", $result ); - - sort( $resultLines ); - - $resultPairs = array(); - - $messageToSignParts = array(); - - foreach( $resultLines as $line ) { - // careful here, because = is used in base-64 encoding - // replace first = in a line (the key/value separator) - // with # - - $lineToParse = preg_replace( '/=/', '#', $line, 1 ); - - // now split on # instead of = - $parts = preg_split( "/#/", $lineToParse ); - - $resultPairs[$parts[0]] = $parts[1]; - - if( $parts[0] != "h" ) { - // include all but signature in message to sign - $messageToSignParts[] = $line; - } - } - $messageToSign = implode( "&", $messageToSignParts ); - - $trueSig = - base64_encode( - hash_hmac( 'sha1', - $messageToSign, - // need to pass in raw key - base64_decode( $yubicoSecretKey ), - true) ); - - if( $trueSig != $resultPairs["h"] ) { - echo "Yubikey authentication failed.
"; - echo "Bad signature from authentication server
"; - die(); - } - - $status = $resultPairs["status"]; - if( $status != "OK" ) { - echo "Yubikey authentication failed: $status"; - die(); - } - - } - - // set cookie again, renewing it, expires in 24 hours - $expireTime = time() + 60 * 60 * 24; - - setcookie( $cookieName, $password_hash, $expireTime, "/" ); - } - } - - - - -function ts_clearPasswordCookie() { - global $tableNamePrefix; - - $cookieName = $tableNamePrefix . "cookie_password_hash"; - - // expire 24 hours ago (to avoid timezone issues) - $expireTime = time() - 60 * 60 * 24; - - setcookie( $cookieName, "", $expireTime, "/" ); - } - - - - - -// found here: -// http://php.net/manual/en/function.fpassthru.php - -function ts_send_file( $path ) { - session_write_close(); - //ob_end_clean(); - - if( !is_file( $path ) || connection_status() != 0 ) { - return( FALSE ); - } - - - //to prevent long file from getting cut off from //max_execution_time - - set_time_limit( 0 ); - - $name = basename( $path ); - - //filenames in IE containing dots will screw up the - //filename unless we add this - - // sometimes user agent is not set! - if( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { - - if( strstr( $_SERVER['HTTP_USER_AGENT'], "MSIE" ) ) { - $name = - preg_replace('/\./', '%2e', - $name, substr_count($name, '.') - 1); - } - } - - - //required, or it might try to send the serving - //document instead of the file - - header("Cache-Control: "); - header("Pragma: "); - header("Content-Type: application/octet-stream"); - header("Content-Length: " .(string)(filesize($path)) ); - header('Content-Disposition: attachment; filename="'.$name.'"'); - header("Content-Transfer-Encoding: binary\n"); - - if( $file = fopen( $path, 'rb' ) ) { - while( ( !feof( $file ) ) - && ( connection_status() == 0 ) ) { - print( fread( $file, 1024*8 ) ); - flush(); - } - fclose($file); - } - return( (connection_status() == 0 ) and !connection_aborted() ); - } - - - - -function ts_hmac_sha1( $inKey, $inData ) { - return hash_hmac( "sha1", - $inData, $inKey ); - } - - -function ts_hmac_sha1_raw( $inKey, $inData ) { - return hash_hmac( "sha1", - $inData, $inKey, true ); - } - - - -// convert a binary string into a "readable" base-32 encoding -function ts_readableBase32Encode( $inBinaryString ) { - global $readableBase32DigitArray; - - $binaryDigits = str_split( $inBinaryString ); - - // string of 0s and 1s - $binString = ""; - - foreach( $binaryDigits as $digit ) { - $binDigitString = decbin( ord( $digit ) ); - - // pad with 0s - $binDigitString = - substr( "00000000", 0, 8 - strlen( $binDigitString ) ) . - $binDigitString; - - $binString = $binString . $binDigitString; - } - - // now have full string of 0s and 1s for $inBinaryString - - return ts_readableBase32EncodeFromBitString( $binString ); - } - - - - -// encodes a string of 0s and 1s into an ASCII readable-base32 string -function ts_readableBase32EncodeFromBitString( $inBitString ) { - global $readableBase32DigitArray; - - - // chunks of 5 bits - $chunksOfFive = str_split( $inBitString, 5 ); - - $encodedString = ""; - foreach( $chunksOfFive as $chunk ) { - $index = bindec( $chunk ); - - $encodedString = $encodedString . $readableBase32DigitArray[ $index ]; - } - - return $encodedString; - } - - - -// decodes an ASCII readable-base32 string into a string of 0s and 1s -function ts_readableBase32DecodeToBitString( $inBase32String ) { - global $readableBase32DigitArray; - - $digits = str_split( $inBase32String ); - - $bitString = ""; - - foreach( $digits as $digit ) { - $index = array_search( $digit, $readableBase32DigitArray ); - - $binDigitString = decbin( $index ); - - // pad with 0s - $binDigitString = - substr( "00000", 0, 5 - strlen( $binDigitString ) ) . - $binDigitString; - - $bitString = $bitString . $binDigitString; - } - - return $bitString; - } - - - -// decodes a ASCII hex string into an array of 0s and 1s -function ts_hexDecodeToBitString( $inHexString ) { - global $readableBase32DigitArray; - - $digits = str_split( $inHexString ); - - $bitString = ""; - - foreach( $digits as $digit ) { - $index = hexdec( $digit ); - - $binDigitString = decbin( $index ); - - // pad with 0s - $binDigitString = - substr( "0000", 0, 4 - strlen( $binDigitString ) ) . - $binDigitString; - - $bitString = $bitString . $binDigitString; - } - - return $bitString; - } - - - - -?> diff --git a/game/ticketServer/settings.php b/game/ticketServer/settings.php deleted file mode 100644 index 01bf80d1..00000000 --- a/game/ticketServer/settings.php +++ /dev/null @@ -1,264 +0,0 @@ - "2010-04-09 00:00:00", - "april_12" => "2010-04-12 00:00:00" ); - -// secret shared with fastspring server, one per purchase tag from above -$fastspringPrivateKeys = array( "april_9" => "secret A", - "april_12" => "secret B" ); - - -// files to serve, from path below -$fileList = array( "sueFamilyWeb.jpg", "SleepIsDeath_v2_UnixSource.tar.gz" ); - -$fileDescriptions = array( - "Sue's family picture, from the archive.", - "Unix (and Mac/Windows) Source Code (notes)" ); - - - -// should not be web-accessible -$downloadFilePath = "/home/jcr13/sidDownloads/"; - - -// should remote mirrors be used instead? -$useRemoteMirrors = 0; - -// one URL per line, each ending with "/" -// appending file names from $fileList directly should produce valid -// download URLs -// -// NOTE: using the mirror system eliminates download security, as these -// URLs do NOT use ticket IDs. -// If one of these URLs leaks, anyone can download the file from the mirror -// -// On the other hand, it makes rolling out new mirrors trivial. -// The trade-off may be acceptable in some cases (a server-based game -// where the download is useless without an account---people will not be -// motivated to waste our bandwidth by downloading it without paying). -$remoteMirrorURLFile = "/home/jcr13/sidDownloads/remoteServerList.ini"; - - - - -// header and footers for various pages -$header = "include( \"header.php\" );"; -$footer = "include( \"footer.php\" );"; - -$fileListHeader = $header . -'echo "
Downloads

"; ' . -'echo "Your account email is: $email

"; '. -'echo "Your Download Code is: $ticket_id


"; '. -'if( $coupon_code != "" ) { '. -' echo "Give this coupon code to a friend: "; '. -' echo "$coupon_code


"; '. -' } '. -'echo "
"; '; - - - - -// parameters for download emails that are sent out -$siteName = "Sleep Is Death"; -$siteEmailAddress = "Jason Rohrer "; -$siteEmailDomain = "cornell.edu"; - -// can be left blank to just give download information -// should contain newlines to separate it from next part of email -// if not blank -$extraEmailMessage = -"Please share the following information with a friend, so that you ". -"have someone to play the game with.\n\n"; - - - - -// number of tickets shown per page in the browse view -$ticketsPerPage = 6; - - -// can users edit their own email? -$canEditEmail = false; - - - -// SMTP settings - -// if off, then raw sendmail is used instead -$useSMTP = 0; - -// SMTP requires that the PEAR Mail package is installed -// set the include path here for Mail.php, if needed: -/* -ini_set( 'include_path', - ini_get( 'include_path' ) . PATH_SEPARATOR . '/home/jcr13/php' ); -*/ - -$smtpHost = "ssl://mail.server.com"; - -$smtpPort = "465"; - -$smtpUsername = "jason@server.com"; - -$smtpPassword = "secret"; - - - -// separate SMTP for mission-critical, transactional emails (like download code -// emails) -// Defaults to being same as the above SMTP, which is used for bulk messages -// (like a note sent to everyone). -$smtpHostTrans = $smtpHost; - -$smtpPortTrans = $smtpPort; - -$smtpUsernameTrans = $smtpUsername; - -$smtpPasswordTrans = $smtpPassword; - - -// set to 1 to use bulk emailer instead of smtp directly -// this is ONLY used for bulk notes to all -$useBulkEmailerForNotes = 1; - -// path to bulkEmailer api -$bulkEmailerPath = "../bulkEmailer/bulkEmailerAPI.php"; - - -// transfering all data to the bulk emailer can still -// take a while, causing PHP gateway timeouts -// Even if timeout wasn't an issue, running a long sever-side -// process is fragile (browser can crash, etc.) -// so split it up into batches. -$bulkEmailBatchSize = 10000; - - - -// key to prove our publisher identity to Steam API -// this key must be kept secret. -$steamWebAPIKey = "REPLACE_ME"; - - -// the app ID that we check ownership for -// example ID is for The Castle Doctrine -$steamAppID = "249570"; - - -?> \ No newline at end of file diff --git a/game/ticketServer/sha1.js b/game/ticketServer/sha1.js deleted file mode 100644 index 491981c0..00000000 --- a/game/ticketServer/sha1.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - A JavaScript implementation of the SHA family of hashes, as - defined in FIPS PUB 180-4 and FIPS PUB 202, as well as the corresponding - HMAC implementation as defined in FIPS PUB 198a - - Copyright Brian Turek 2008-2016 - Distributed under the BSD License - See http://caligatio.github.com/jsSHA/ for more information - - Several functions taken from Paul Johnston -*/ -'use strict';(function(G){function t(e,a,d){var g=0,c=[],b=0,f,k,l,h,m,w,n,y,p=!1,q=[],t=[],v,u=!1;d=d||{};f=d.encoding||"UTF8";v=d.numRounds||1;l=z(a,f);if(v!==parseInt(v,10)||1>v)throw Error("numRounds must a integer >= 1");if("SHA-1"===e)m=512,w=A,n=H,h=160,y=function(a){return a.slice()};else throw Error("Chosen SHA variant is not supported");k=x(e);this.setHMACKey=function(a,b,c){var d;if(!0===p)throw Error("HMAC key already set");if(!0===u)throw Error("Cannot set HMAC key after calling update"); -f=(c||{}).encoding||"UTF8";b=z(b,f)(a);a=b.binLen;b=b.value;d=m>>>3;c=d/4-1;if(da/8){for(;b.length<=c;)b.push(0);b[c]&=4294967040}for(a=0;a<=c;a+=1)q[a]=b[a]^909522486,t[a]=b[a]^1549556828;k=w(q,k);g=m;p=!0};this.update=function(a){var d,e,f,h=0,n=m>>>5;d=l(a,c,b);a=d.binLen;e=d.value;d=a>>>5;for(f=0;f>>5);b=a%m;u=!0};this.getHash=function(a,d){var f,l,m,r;if(!0=== -p)throw Error("Cannot call getHash after setting HMAC key");m=B(d);switch(a){case "HEX":f=function(a){return C(a,h,m)};break;case "B64":f=function(a){return D(a,h,m)};break;case "BYTES":f=function(a){return E(a,h)};break;case "ARRAYBUFFER":try{l=new ArrayBuffer(0)}catch(I){throw Error("ARRAYBUFFER not supported by this environment");}f=function(a){return F(a,h)};break;default:throw Error("format must be HEX, B64, BYTES, or ARRAYBUFFER");}r=n(c.slice(),b,g,y(k),h);for(l=1;l>>3;if(0!==g%2)throw Error("String of HEX type must be in byte increments");for(c=0;c>>1)+l;for(f=k>>>2;a.length<=f;)a.push(0);a[f]|=b<<8*(3-k%4)}return{value:a,binLen:4*g+d}}function K(e,a,d){var g=[],c,b,f,k,g=a||[0];d=d||0;b=d>>>3;for(c=0;c>>2,g.length<=f&&g.push(0),g[f]|=a<<8*(3-k%4);return{value:g,binLen:8*e.length+d}}function L(e,a,d){var g=[],c=0,b,f,k,l,h,m,g=a||[0];d=d||0;a=d>>>3;if(-1===e.search(/^[a-zA-Z0-9=+\/]+$/))throw Error("Invalid character in base-64 string");f=e.indexOf("=");e=e.replace(/\=/g,"");if(-1!==f&&f