Temporary repo for server-side PHP code related to MapTool
So far, this repo will be used only for MapTool-related server-side code. That means all code associated with the following subdomains of rptools.net:
- services (used for registering new servers and finding out which servers are available)
The goal is to add new subdomains as new functionality is needed for MapTool. For example:
- registry (where MT sends information about new servers started with a name)
- updates (where MT checks to see whether a newer version is available)
- stacktraces (where MT uploads stack traces generated by Java exception handling)
This module represents an AJAX interface to be used by MapTool when it wants to upload a stacktrace such as that produced by a Java exception. The goal is for this to be generic enough that it can be used by other RPTools applications in the future.
MapTool contacts this script (via POST) and provides:
- its version number,
- a timestamp,
- a checksum of the unencrypted stacktrace text, and
- a hash digest of the above JSON data (HMAC).
If we already have the checksum in our database, it means the crash is a duplicate and we can tell MT not to bother sending it.
A digest of the above using "RPTools.net" as a salt ensures the request is valid -- a spammer wouldn't know how to build the digest without MT source code. The salt could be the MT version number, MT's timestamp value, a previously defined shared secret, or some combination of any of these. All that's important is that a spammer won't know what it is without looking at MT's source code. (In a web application, this communication would be over HTTPS but RPTools is not going to pay for a certificate! We could have MT generate a public/private key pair on the fly and send its public key to the server so that all traffic was encrypted, but this is a lot of extra cpu work without much payoff -- we're only trying to weed out spammers, after all.)
json={
"body": {
"version": "1.4.0.1",
"clienttime": 123456789,
"checksum": 987654321
},
"digest": "7a6f548e9237d990c876a"
}
// Corresponding PHP code (assuming all validation is successful)
// ($body is PHP object; will be converted to string by json_encode())
$digest = calcDigest($body);
if ($digest !== $json["digest"]) {
//print_r($digest);
failure("Digest mismatch");
}
print "Success. So far. :)\n";
The server then generates a public/private key and responds back to MT with:
- the public key,
- a hash of MT's version+timestamp (using the same shared secret),
- the server's timestamp, and
- the URL of where to send the ZIP file with the stacktrace in it.
The URL will be this script plus a QUERY_STRING parameter that contains a random number. MT can check the hash of the version+timestamp; if it's not as expected, the server isn't who we think it is and MT breaks the connection. (The server's timestamp need not match MT's. They're only used on each end for timeouts enforced on that end. Because HTTP is stateless, this does mean that the timestamp needs to be passed back and forth each time, but the digest protects the autheniticity of the value so it can't be corrupted externally.)
json={
"body": {
"publickey": "12345abcdef6789",
"hash": "827648d9a866f8e9c",
"clienttime": 123456789,
"servertime": 123458294,
"url": THIS_SCRIPT + "?r=" + RANDOM_NUMBER
},
"digest": "2345263456345"
}
Now MT encrypts the ZIP file using the public key and PUT's it to the server, passing the hashed servertime in the QUERY_STRING. If the servertime is outside the required time frame, the server ignores the uploaded file. The server can also verify the checksum of the stacktrace inside the ZIP and compare it to the checksum in the first exchange. If they don't match, the server can ignore the uploaded file and send an error back to MT.
Throughout all of the above steps, there should be a relatively short time span involved, perhaps 15 minutes. Both ends will embed their starting timestamp into the conversation so that either end can timeout without acknowledgment from the other end. MT should probably only try once or twice to upload the file and should forget about the upload if unsuccessful in the first couple of attempts.
Note that the size of the uploaded ZIP file should be very small; the contents are 100% text and will compress well, and none of the JSON structures shown above will be larger than a few hundred bytes at most.
Once we have the uploaded the ZIP file, we arrange to get it to the developers, perhaps by attaching it to a github issue? The ZIP file should include two files:
- the sanitized output from the Help>Debug menu option within MT, and
- the UTF-8 text contents of the stacktrace itself.
Over time we may find it necessary to add more info.