| 1 | <?php |
|---|
| 2 | //HTTP Digest authentication code, modified from http://php.net/manual/en/features.http-auth.php |
|---|
| 3 | define('HTTP_DIGEST_REALM', 'Build Server'); |
|---|
| 4 | |
|---|
| 5 | //Function to challenge the user |
|---|
| 6 | function http_digest_challenge() { |
|---|
| 7 | header('HTTP/1.1 401 Unauthorized'); |
|---|
| 8 | header(sprintf('WWW-Authenticate: Digest realm="%s",qop="auth",nonce="%s",opaque="%s"', |
|---|
| 9 | HTTP_DIGEST_REALM, uniqid(), md5(HTTP_DIGEST_REALM))); |
|---|
| 10 | exit; |
|---|
| 11 | } |
|---|
| 12 | |
|---|
| 13 | //Function to parse the HTTP auth header |
|---|
| 14 | function http_digest_parse($txt) { |
|---|
| 15 | // protect against missing data |
|---|
| 16 | $needed_parts = array('nonce' => 1, |
|---|
| 17 | 'nc' => 1, |
|---|
| 18 | 'cnonce' => 1, |
|---|
| 19 | 'qop' => 1, |
|---|
| 20 | 'username' => 1, |
|---|
| 21 | 'uri' => 1, |
|---|
| 22 | 'response' => 1 |
|---|
| 23 | ); |
|---|
| 24 | $data = array(); |
|---|
| 25 | |
|---|
| 26 | preg_match_all('@(\w+)=(?:(?:\'([^\']+)\'|"([^"]+)")|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER); |
|---|
| 27 | |
|---|
| 28 | foreach ($matches as $m) |
|---|
| 29 | { |
|---|
| 30 | $data[$m[1]] = $m[2] ? $m[2] : ($m[3] ? $m[3] : $m[4]); |
|---|
| 31 | unset($needed_parts[$m[1]]); |
|---|
| 32 | } |
|---|
| 33 | |
|---|
| 34 | return $needed_parts ? false : $data; |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | //user => password |
|---|
| 38 | $users = array('admin' => 'mypass', 'guest' => 'guest'); |
|---|
| 39 | |
|---|
| 40 | //Challenge the client if we did not receive the digest |
|---|
| 41 | if (empty($_SERVER['PHP_AUTH_DIGEST'])) |
|---|
| 42 | http_digest_challenge(); |
|---|
| 43 | |
|---|
| 44 | //Analyze the PHP_AUTH_DIGEST variable |
|---|
| 45 | $credentials = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']); |
|---|
| 46 | if (!$credentials || !isset($users[$credentials['username']])) |
|---|
| 47 | http_digest_challenge(); |
|---|
| 48 | |
|---|
| 49 | //Check the response |
|---|
| 50 | $A1 = md5($credentials['username'] . ':' . HTTP_DIGEST_REALM . ':' . $users[$credentials['username']]); |
|---|
| 51 | $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $credentials['uri']); |
|---|
| 52 | $valid_response = md5($A1 . ':' . $credentials['nonce'] . ':' . $credentials['nc'] . ':' . |
|---|
| 53 | $credentials['cnonce'] . ':' . $credentials['qop'] . ':' . $A2); |
|---|
| 54 | if ($credentials['response'] != $valid_response) |
|---|
| 55 | http_digest_challenge(); |
|---|
| 56 | |
|---|
| 57 | require_once('Build.php'); |
|---|
| 58 | require_once('BuildUtil.php'); |
|---|
| 59 | require_once('BuildBranch.php'); |
|---|
| 60 | require_once('Credentials.php'); |
|---|
| 61 | require_once('Database.php'); |
|---|
| 62 | |
|---|
| 63 | try |
|---|
| 64 | { |
|---|
| 65 | //Check that we have all the necessary information |
|---|
| 66 | $branches = BuildBranch::Get(); |
|---|
| 67 | if (!array_key_exists($_GET['branch'], $branches)) |
|---|
| 68 | throw new Exception('The branch ' . $_GET['branch'] . ' does not exist.'); |
|---|
| 69 | if (!is_numeric($_GET['revision']) || !is_numeric($_GET['filesize']) || empty($_GET['url'])) |
|---|
| 70 | throw new Exception('Invalid build information provided.'); |
|---|
| 71 | |
|---|
| 72 | //Get the branch the notification is for |
|---|
| 73 | $branch = $branches[$_GET['branch']]; |
|---|
| 74 | |
|---|
| 75 | //Insert the build to the database. |
|---|
| 76 | ob_start(); |
|---|
| 77 | printf('Inserting build into database... '); |
|---|
| 78 | Build::CreateBuild($branch->ID, intval($_GET['revision']), intval($_GET['filesize']), $_GET['url']); |
|---|
| 79 | printf("Inserted.\n"); |
|---|
| 80 | |
|---|
| 81 | //Remove old builds |
|---|
| 82 | printf('Removing old builds from database...' . "\n"); |
|---|
| 83 | |
|---|
| 84 | $pdo = new Database(); |
|---|
| 85 | $statement = $pdo->prepare('UPDATE downloads SET Superseded=1 WHERE DownloadID=?'); |
|---|
| 86 | |
|---|
| 87 | $builds = Build::GetActive($branch->ID); |
|---|
| 88 | for ($i = 0, $j = count($builds) - 3; $i < $j; ++$i) |
|---|
| 89 | { |
|---|
| 90 | printf("\n\t" . 'Removing build %s' . "\n\t\t", $builds[$i]->Name); |
|---|
| 91 | |
|---|
| 92 | //Delete the copy on the SourceForge web server. |
|---|
| 93 | Delete(SHELL_WEB_ROOT . parse_url($builds[$i]->Link, PHP_URL_PATH), $sftp_username, |
|---|
| 94 | $sftp_password); |
|---|
| 95 | |
|---|
| 96 | //Remove from the database |
|---|
| 97 | $statement->execute(array($builds[$i]->ID)); |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | header('content-type: text/plain'); |
|---|
| 101 | ob_end_flush(); |
|---|
| 102 | } |
|---|
| 103 | catch (Exception $e) |
|---|
| 104 | { |
|---|
| 105 | ob_end_clean(); |
|---|
| 106 | header('500 Internal Server Error'); |
|---|
| 107 | echo $e->getMessage(); |
|---|
| 108 | } |
|---|
| 109 | ?> |
|---|