Better logging
rodzic
b69c08e5bb
commit
70404d1b12
12
README.md
12
README.md
|
@ -14,18 +14,22 @@ There are no tests, no checks, no security features, no formal verifications, no
|
|||
1. Visit `https://test.example.com/.well-known/webfinger` and check that it shows a JSON file with your user's details.
|
||||
1. Go to Mastodon or other Fediverse site and search for your user: `@username@test.example.com`
|
||||
1. Follow your user.
|
||||
1. Check your `/logs/` directory to see if the follow request was received correctly.
|
||||
1. Check your `/data/logs/` directory to see if the follow request was received correctly.
|
||||
1. To post a message, visit `https://test.example.com/write` type in your message and password. Press the "Post Message" button.
|
||||
1. Check social media to see if the message appears.
|
||||
1. To follow other users, visit `https://test.example.com/follow` type in the name of the user you want to follow and your password. Press the "Send Follow Request" button.
|
||||
1. Check social media to see if the follow request came through.
|
||||
|
||||
## How this works
|
||||
|
||||
* The `.htaccess` file transforms requests from `example.com/whatever` to `example.com/index.php?path=whatever`.
|
||||
* The `index.php` file performs a specific action depending on the path requested.
|
||||
* Log files are saved as .txt in the `/logs` directory.
|
||||
* Log files are saved as .txt in the `/data/logs` directory.
|
||||
* Post files are saved as .json in the `/posts` directory.
|
||||
* Followers' details are saved as .json in the `/data/followers` directory.
|
||||
* This has sloppy support for linking #hashtags, https:// URls, and @ mentions.
|
||||
* Details of accounts who follow you are saved as .json in the `/data/followers` directory.
|
||||
* Details of accounts who you follow are saved as .json in the `/data/following` directory.
|
||||
* Messages sent to your inbox are saved as .json in the `/data/inbox` directory.
|
||||
* This has sloppy support for sending posts with linked #hashtags, https:// URls, and @ mentions.
|
||||
* HTTP Message Signatures are verified.
|
||||
|
||||
## Requirements
|
||||
|
|
82
index.php
82
index.php
|
@ -41,8 +41,21 @@
|
|||
// Internal data
|
||||
$server = $_SERVER["SERVER_NAME"]; // Do not change this!
|
||||
|
||||
// Set up where logs and messages go
|
||||
$data = "data";
|
||||
$directories = array(
|
||||
"inbox" => "{$data}/inbox",
|
||||
"followers" => "{$data}/followers",
|
||||
"following" => "{$data}/following",
|
||||
"logs" => "{$data}/logs",
|
||||
"posts" => "posts",
|
||||
);
|
||||
foreach ( $directories as $directory ) {
|
||||
if( !is_dir( $directory ) ) { mkdir( $data ); mkdir( $directory ); }
|
||||
}
|
||||
|
||||
// Logging:
|
||||
// ActivityPub is a "chatty" protocol. This takes all the requests your server receives and saves them in `/logs/` as a datestamped text file.
|
||||
// ActivityPub is a "chatty" protocol. This takes all the requests your server receives and saves them as a datestamped text file.
|
||||
|
||||
// Get all headers and requests sent to this server
|
||||
$headers = print_r( getallheaders(), true );
|
||||
|
@ -59,10 +72,10 @@
|
|||
// Get the type of request - used in the log filename
|
||||
if ( isset( $body["type"] ) ) {
|
||||
// Sanitise before using it in a filename
|
||||
$type = " " . urlencode( $body["type"] );
|
||||
$type = "." . urlencode( $body["type"] );
|
||||
} else {
|
||||
// Sanitise the path requested
|
||||
$type = " " . urlencode( $path );
|
||||
$type = "." . urlencode( $path );
|
||||
}
|
||||
|
||||
// Create a timestamp for the filename
|
||||
|
@ -74,9 +87,7 @@
|
|||
$filename = "{$timestamp}{$type}.txt";
|
||||
|
||||
// Save headers and request data to the timestamped file in the logs directory
|
||||
if( ! is_dir( "logs" ) ) { mkdir( "logs"); }
|
||||
|
||||
file_put_contents( "logs/{$filename}",
|
||||
file_put_contents( $directories["logs"] . "/{$filename}",
|
||||
"Headers: \n$headers \n\n" .
|
||||
"Body Data: \n$bodyData \n\n" .
|
||||
"POST Data: \n$postData \n\n" .
|
||||
|
@ -222,7 +233,7 @@
|
|||
// The details of the remote user's server is saved to a file so that future messages can be delivered to the follower.
|
||||
// An accept request is cryptographically signed and POST'd back to the remote server.
|
||||
function inbox() {
|
||||
global $body, $server, $username, $key_private;
|
||||
global $body, $server, $username, $key_private, $directories;
|
||||
|
||||
// Validate HTTP Message Signature
|
||||
// This logs whether the signature was validated or not
|
||||
|
@ -232,6 +243,19 @@
|
|||
$inbox_message = $body;
|
||||
$inbox_type = $inbox_message["type"];
|
||||
|
||||
// Save any Follow, Create, Announce, Like messages
|
||||
// This ignores Delete, Undo, and anything else
|
||||
if ( match( $inbox_type ) {
|
||||
"Follow", "Create", "Announce", "Like" => true,
|
||||
default => false,
|
||||
} ) {
|
||||
// Save the message in `/data/inbox/`
|
||||
$timestamp = ( new DateTime() )->format( DATE_RFC3339_EXTENDED );
|
||||
$inbox_filename = $timestamp . "." . urlencode( $inbox_type ) . ".json";
|
||||
file_put_contents( $directories["inbox"] . "/{$inbox_filename}", json_encode( $inbox_message ) );
|
||||
}
|
||||
|
||||
|
||||
// This inbox only responds to follow requests
|
||||
if ( "Follow" != $inbox_type ) { die(); }
|
||||
|
||||
|
@ -270,9 +294,8 @@
|
|||
curl_close($ch);
|
||||
|
||||
// Save the actor's data in `/data/followers/`
|
||||
if( ! is_dir( "data/followers" ) ) { mkdir( "data"); mkdir( "data/followers"); }
|
||||
$follower_filename = urlencode( $follower_actor );
|
||||
file_put_contents( "data/followers/{$follower_filename}.json", $inbox_actor_json );
|
||||
file_put_contents( $directories["followers"] . "/{$follower_filename}.json", $inbox_actor_json );
|
||||
|
||||
} else {
|
||||
die();
|
||||
|
@ -316,9 +339,10 @@
|
|||
|
||||
// Check for errors
|
||||
if( curl_errno( $ch ) ) {
|
||||
file_put_contents( "error.txt", curl_error( $ch ) );
|
||||
$timestamp = ( new DateTime() )->format( DATE_RFC3339_EXTENDED );
|
||||
file_put_contents( $directories["logs"] . "/{$timestamp}.Error.txt", curl_error( $ch ) );
|
||||
}
|
||||
curl_close($ch);
|
||||
curl_close( $ch );
|
||||
die();
|
||||
}
|
||||
|
||||
|
@ -507,7 +531,7 @@ HTML;
|
|||
// It constructs a list of shared inboxes and unique inboxes
|
||||
// It sends the message to every server that is following this account.
|
||||
function send() {
|
||||
global $password, $server, $username, $key_private;
|
||||
global $password, $server, $username, $key_private, $directories;
|
||||
|
||||
// Does the posted password match the stored password?
|
||||
if( $password != $_POST["password"] ) { die(); }
|
||||
|
@ -599,8 +623,7 @@ HTML;
|
|||
// Save the permalink
|
||||
$note_json = json_encode( $note );
|
||||
// Check for posts/ directory and create it
|
||||
if( ! is_dir( "posts" ) ) { mkdir( "posts"); }
|
||||
file_put_contents( "posts/{$guid}.json", print_r( $note_json, true ) );
|
||||
file_put_contents( $directories["posts"] . "/{$guid}.json", print_r( $note_json, true ) );
|
||||
|
||||
// Read existing followers
|
||||
$followers = glob( "data/followers/*.json" );
|
||||
|
@ -795,7 +818,7 @@ HTML;
|
|||
<input name="user" id="user" type="text" size="32" placeholder="@user@example.com" /><br>
|
||||
<label for="password">Password</label><br>
|
||||
<input name="password" id="password" type="password" size="32"><br>
|
||||
<input type="submit" value="Post Message">
|
||||
<input type="submit" value="Send Follow Request">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -808,7 +831,7 @@ HTML;
|
|||
// Then it sends a follow request
|
||||
// If the request is accepted, it saves the details in `data/following/` as a JSON file
|
||||
function follow_user() {
|
||||
global $password, $server, $username, $key_private;
|
||||
global $password, $server, $username, $key_private, $directories;
|
||||
|
||||
// Does the posted password match the stored password?
|
||||
if( $password != $_POST["password"] ) { echo "Wrong Password!"; die(); }
|
||||
|
@ -869,15 +892,14 @@ HTML;
|
|||
|
||||
// Check for errors
|
||||
if( curl_errno( $ch ) ) {
|
||||
file_put_contents( "error.txt", curl_error( $ch ) );
|
||||
$timestamp = ( new DateTime() )->format( DATE_RFC3339_EXTENDED );
|
||||
file_put_contents( $directories["logs"] . "/{$timestamp}.Error.txt", curl_error( $ch ) );
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
// Save the user's details
|
||||
// Save headers and request data to the timestamped file in the logs directory
|
||||
if( ! is_dir( "data/following" ) ) { mkdir( "data"); mkdir( "data/following"); }
|
||||
$following_filename = urlencode( $profileURl );
|
||||
file_put_contents( "data/following/{$following_filename}.json", $profileJSON );
|
||||
file_put_contents( $directories["following"] . "/{$following_filename}.json", $profileJSON );
|
||||
|
||||
// Render the JSON so the user can see the POST has worked
|
||||
header( "Location: https://{$server}/data/following/" . urlencode( $following_filename ) . ".json" );
|
||||
|
@ -888,7 +910,7 @@ HTML;
|
|||
// This is optional
|
||||
// It is very confusing
|
||||
function verifyHTTPSignature() {
|
||||
global $input, $body, $server;
|
||||
global $input, $body, $server, $directories;
|
||||
|
||||
// Get the headers send with the request
|
||||
$headers = getallheaders();
|
||||
|
@ -907,12 +929,10 @@ HTML;
|
|||
// Write a log detailing the error
|
||||
$timestamp = ( new DateTime() )->format( DATE_RFC3339_EXTENDED );
|
||||
// Filename for the log
|
||||
$filename = "{$timestamp} Time Failure.txt";
|
||||
$filename = "{$timestamp}.Signature.Time_Failure.txt";
|
||||
|
||||
// Save headers and request data to the timestamped file in the logs directory
|
||||
if( !is_dir( "logs" ) ) { mkdir( "logs"); }
|
||||
|
||||
file_put_contents( "logs/{$filename}",
|
||||
file_put_contents( $directories["logs"] . "/{$filename}",
|
||||
"Original Date:\n" . print_r( $dateHeader, true ) . "\n" .
|
||||
"Local Date:\n" . print_r( $currentDatetime->format('D, d M Y H:i:s T'), true ) . "\n"
|
||||
);
|
||||
|
@ -944,12 +964,10 @@ HTML;
|
|||
// Write a log detailing the error
|
||||
$timestamp = ( new DateTime() )->format( DATE_RFC3339_EXTENDED );
|
||||
// Filename for the log
|
||||
$filename = "{$timestamp} Digest Failure.txt";
|
||||
$filename = "{$timestamp}.Signature.Digest_Failure.txt";
|
||||
|
||||
// Save headers and request data to the timestamped file in the logs directory
|
||||
if( ! is_dir( "logs" ) ) { mkdir( "logs"); }
|
||||
|
||||
file_put_contents( "logs/{$filename}",
|
||||
file_put_contents( $directories["logs"] . "/{$filename}",
|
||||
"Original Input:\n" . print_r( $input, true ) . "\n" .
|
||||
"Original Digest:\n" . print_r( $digestString, true ) . "\n" .
|
||||
"Calculated Digest:\n" . print_r( $digestCalculated, true ) . "\n"
|
||||
|
@ -1028,12 +1046,10 @@ HTML;
|
|||
// Write a log detailing the signature verification process
|
||||
$timestamp = ( new DateTime() )->format( DATE_RFC3339_EXTENDED );
|
||||
// Filename for the log
|
||||
$filename = "{$timestamp} Signature ". json_encode( $verified ) . ".txt";
|
||||
$filename = "{$timestamp}.Signature.". json_encode( $verified ) . ".txt";
|
||||
|
||||
// Save headers and request data to the timestamped file in the logs directory
|
||||
if( ! is_dir( "logs" ) ) { mkdir( "logs"); }
|
||||
|
||||
file_put_contents( "logs/{$filename}",
|
||||
file_put_contents( $directories["logs"] . "/{$filename}",
|
||||
"Original Body:\n" . print_r( $body, true ) . "\n\n" .
|
||||
"Original Headers:\n" . print_r( $headers, true ) . "\n\n" .
|
||||
"Signature Headers:\n" . print_r( $signatureHeaders, true ) . "\n\n" .
|
||||
|
|
Ładowanie…
Reference in New Issue