| <?php | |
| /** | |
| * Copyright (c) Eclipse Foundation and others. | |
| * | |
| * This program and the accompanying materials are made | |
| * available under the terms of the Eclipse Public License 2.0 | |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ | |
| * | |
| * SPDX-License-Identifier: EPL-2.0 | |
| */ | |
| require_once (dirname(__FILE__) . "/debug.php"); | |
| trace_file_info(__FILE__); | |
| /* | |
| * The regular expression pattern that is used to determine whether | |
| * or not a project id is valid. | |
| * PRIVATE: THIS FIELD IS NOT API. | |
| */ | |
| $projectNameSegmentPattern = "[a-zA-Z0-9\\-]+"; | |
| $projectNamePattern = "$projectNameSegmentPattern(\\.$projectNameSegmentPattern){0,2}"; | |
| define('ProjectNamePattern', $projectNamePattern); | |
| /** | |
| * Answers <code>true</code> if $id represents a valid project id; | |
| * <code>false</code> otherwise. | |
| * | |
| * @param string $id | |
| * Must not be <code>null</code> | |
| * @return bool | |
| */ | |
| function isValidProjectId($id) { | |
| global $projectNamePattern; | |
| return preg_match("/^$projectNamePattern$/", $id); | |
| } | |
| /** | |
| * This function normalizes the provided URL to a valid 'eclipse.org' HTTP | |
| * form. | |
| * Input should be a valid eclipse.org URL or a relative URL | |
| * (with or without a leading slash). Note that URLs that do not correspond | |
| * to an eclipse.org addresses, will result in a <code>null</code> result. | |
| * | |
| * Note that this is more about normalization than actual full validation; | |
| * only the scheme and domain are considered. The current implementation | |
| * only supports the http/https schemes; the specification of a port | |
| * is not supported. This may change in the future. | |
| * | |
| * e.g. The following URLs are all considered valid and returned in the | |
| * the form they are provided. | |
| * - http://www.eclipse.org/woolsey/para.html | |
| * - http://eclipse.org/woolsey/para.html | |
| * - http://download.eclipse.org/woolsey/para.html | |
| * - | |
| * http://git.eclipse.org/c/jetty/org.eclipse.jetty.admin.git/plain/jetty-project-plan.xml | |
| * | |
| * e.g. The following URLs will be returned as | |
| * http://eclipse.org/woolsey/para.html | |
| * - woolsey/para.html | |
| * - /woolsey/para.html | |
| * | |
| * Usage: | |
| * | |
| * normalizeHttpUrl('http://www.eclipse.org/woolsey/para.html'); | |
| * | |
| * @param string $url | |
| * Must not be <code>null</code> | |
| * @return string | |
| */ | |
| function normalizeHttpUrl($url) { | |
| if (preg_match('/^https?:\/\/(\w+\.)?eclipse\.org(\/.*)?$/', $url)) | |
| return $url; | |
| if (preg_match('/^https?:\/\/(\w+\.)?locationtech\.org(\/.*)?$/', $url)) | |
| return $url; | |
| if (preg_match('/^https?:\/\/(\w+\.)?polarsys\.org(\/.*)?$/', $url)) | |
| return $url; | |
| $relative = normalizeRelativeUrl($url, 'www'); | |
| if ($relative) | |
| return 'http://www.eclipse.org' . $relative; | |
| return null; | |
| } | |
| /** | |
| * This function normalizes the provided URL to valid file path on the | |
| * eclipse.org web directory. | |
| * Input should be a valid eclipse.org URL | |
| * or a relative URL (with or without a leading slash). | |
| * | |
| * e.g. The following URLs will all normalize to | |
| * /home/local/data/httpd/www.eclipse.org/html/woolsey/para.html | |
| * | |
| * - http://www.eclipse.org/woolsey/para.html | |
| * - http://eclipse.org/woolsey/para.html | |
| * - http://localhost/woolsey/para.html | |
| * - woolsey/para.html | |
| * - /woolsey/para.html) | |
| * | |
| * Note that URLs that do not correspond to eclipse.org addresses, will | |
| * result in a <code>null</code> result. | |
| * | |
| * Usage: | |
| * | |
| * normalizeFilePathUrl('http://www.eclipse.org/woolsey/para.html'); | |
| * | |
| * @param string $url | |
| * Must not be <code>null</code> | |
| * @return string | |
| */ | |
| function normalizeFilePathUrl($url) { | |
| global $_SERVER; | |
| $relative = normalizeRelativeUrl($url); | |
| if (!$relative) | |
| return null; | |
| return $_SERVER['DOCUMENT_ROOT'] . $relative; | |
| } | |
| /** | |
| * This function normalizes the provided URL to a relative path. | |
| * Input should be a valid eclipse.org URL or a relative URL | |
| * (with or without a leading slash). | |
| * | |
| * e.g. The following URLs will all normalize to | |
| * /woolsey/para.html | |
| * | |
| * - http://www.eclipse.org/woolsey/para.html | |
| * - http://eclipse.org/woolsey/para.html | |
| * - http://localhost/woolsey/para.html | |
| * - woolsey/para.html | |
| * - /woolsey/para.html) | |
| * | |
| * Note that URLs that do not correspond to eclipse.org addresses, will | |
| * result in a <code>null</code> result. | |
| * | |
| * Usage: | |
| * | |
| * normalizeRelativeUrl('http://www.eclipse.org/woolsey/para.html'); | |
| * | |
| * @param string $url | |
| * Must not be <code>null</code> | |
| * @return string | |
| */ | |
| function normalizeRelativeUrl($url) { | |
| if (!$url) | |
| return null; | |
| $url = trim($url); | |
| $pattern_word = '\w[\w-]*'; | |
| $pattern_segment = "$pattern_word(\\.$pattern_word)*"; | |
| $pattern_relative_part = "$pattern_segment(\\/$pattern_segment)*\\/?"; | |
| $pattern_relative_url = "/^\\/?($pattern_relative_part)$/"; | |
| $pattern_http_url = "/^http:\\/\\/(www\\.)?eclipse\\.org\\/($pattern_relative_part)$/"; | |
| $pattern_http_local_url = "/^http:\\/\\/localhost\\/($pattern_relative_part)$/"; | |
| if (preg_match($pattern_relative_url, $url, $matches1)) { | |
| return '/' . $matches1[1]; | |
| } | |
| else | |
| if (preg_match($pattern_http_url, $url, $matches2)) { | |
| return '/' . $matches2[2]; | |
| } | |
| else | |
| if (preg_match($pattern_http_local_url, $url, $matches3)) { | |
| return '/' . $matches3[1]; | |
| } | |
| else { | |
| trace("The url ($url) cannot be normalized."); | |
| return null; | |
| } | |
| } | |
| /** | |
| * If the user is logged in and is either an Eclipse committer | |
| * or a staff member of the Eclipse Foundation, this method | |
| * returns without side effect. If there is no currently logged | |
| * in user, the user is redirected to the login page. If the | |
| * currently logged in user is not a committer or an employee, | |
| * they are redirected to the /project page and the exit() | |
| * function is called (i.e. execution of the caller is truncated). | |
| * | |
| * This function assumes that the $App variable exists and has been | |
| * assigned an instance of the App class (from app.class.php). | |
| * | |
| * @deprecated | |
| * @see callIfNotCommitter() | |
| * | |
| * @param Tracer $trace | |
| * (optional) | |
| * @return Friend | |
| */ | |
| function mustBeCommitter($trace = null) { | |
| global $App; | |
| if ($App->devmode) | |
| return; | |
| require_once ($_SERVER['DOCUMENT_ROOT'] . "/eclipse.org-common/classes/friends/friend.class.php"); | |
| require_once ($_SERVER['DOCUMENT_ROOT'] . "/eclipse.org-common/system/eclipseenv.class.php"); | |
| $Session = $App->useSession("optional"); | |
| $friend = $Session->getFriend(); | |
| // FIXME Hack: Foundation employees have privileged access. | |
| // TODO There may be a better way to do this. | |
| if ($friend && preg_match('/^.+@eclipse-foundation\.org$/', $friend->getEmail())) { | |
| return $friend; | |
| } | |
| $EclipseEnv = new EclipseEnv(); | |
| $domain = $EclipseEnv->getEclipseEnv(); | |
| if (!$friend->getLDAPUID()) { | |
| header("Location: https://" . $domain["accounts"] . "/user/login?takemeback=" . $_SERVER['SCRIPT_URI']); | |
| exit(); | |
| } | |
| if (!$trace) | |
| $trace = trace("Must be committer"); | |
| $trace->trace("UUID: " . $friend->getLDAPUID()); | |
| if (!$friend->getIsCommitter()) { | |
| header("Location: /projects"); | |
| exit(); | |
| } | |
| $trace->trace("User is a committer."); | |
| return $friend; | |
| } | |
| /** | |
| * Test to see if the user is a committer, and execute | |
| * the callable if they are not. | |
| * | |
| * @param callable $function | |
| */ | |
| function callIfNotCommitter($function) { | |
| global $App; | |
| if ($App->devmode) { | |
| return; | |
| } | |
| $Session = $App->useSession("required"); | |
| $friend = $Session->getFriend(); | |
| // TODO There may be a better way to do this. | |
| if (preg_match('/^.+@eclipse-foundation\.org$/', $friend->getEmail())) { | |
| return; | |
| } | |
| if (!$friend->getIsCommitter()) { | |
| call_user_func($function); | |
| } | |
| } | |
| /** | |
| * This function forces a login event if the current user is not | |
| * logged in. | |
| * If the logged in user is not an Eclipse Foundation | |
| * employee, they are redirected to the /projects/ page. It must | |
| * be called before any HTML is written to the output stream. | |
| * | |
| * This function assumes that the $App variable exists and has been | |
| * assigned an instance of the App class (from app.class.php). | |
| * | |
| * @return Friend | |
| */ | |
| function mustBeFoundationEmployee() { | |
| global $App; | |
| if ($App->devmode) | |
| return; | |
| $session = $App->useSession('required'); | |
| $friend = $session->getFriend(); | |
| // TODO There may be a better way to do this. | |
| if (!preg_match('/^.+@eclipse-foundation\.org$/', $friend->getEmail())) { | |
| header("Location: /projects"); | |
| exit(); | |
| } | |
| return $friend; | |
| } | |
| /** | |
| * This function basically throws a fit if the caller is | |
| * coming from anywhere outside of the EF. | |
| * It determines | |
| * whether or not to grant access based on the IP Address. | |
| */ | |
| function mustBeEclipseFoundationCaller() { | |
| global $App; | |
| $App->preventCaching(); | |
| $ip = $App->getRemoteIPAddress (); | |
| $patterns = array ( | |
| '198.41.30.', // 198.41.30.192/26 | |
| '99.240.80.', | |
| '172.25.', // 172.25.0.0/16 | |
| '172.30.', // 172.30.0.0/16 | |
| '127.0.0.1', | |
| '::1' | |
| ); | |
| $match = preg_replace ( '/\./', '\.', implode ( '|', $patterns ) ); | |
| if (preg_match ( "/^($match)/", $ip )) | |
| return; | |
| echo "{$ip} is an invalid caller\n"; | |
| exit (); | |
| } | |
| function getUrlContents($url) { | |
| $ch = curl_init(); | |
| curl_setopt($ch, CURLOPT_URL, $url); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
| $page = curl_exec($ch); | |
| curl_close($ch); | |
| return $page; | |
| } | |
| function implodeWithConjunction($values, $conjunction = 'and', $start = 0) { | |
| $end = count($values) - 1; | |
| if ($start > $end) { | |
| return; | |
| } elseif ($start == $end) { | |
| return $values[$start]; | |
| } elseif ($end - $start == 1) { | |
| return $values[$start] . ', ' . $conjunction . ' ' . $values[$end]; | |
| } else { | |
| return $values[$start] . ', ' . implodeWithConjunction($values, $conjunction, $start + 1); | |
| } | |
| } | |
| function renderAsHeaderComment($string, $length=80) { | |
| $output = array(); | |
| $output[] = '/' . str_repeat('*', $length); | |
| foreach(explode("\n", $string) as $line) { | |
| foreach(explode("\n", wordwrap($line, $length-5)) as $fragment) { | |
| $output[] = ' * ' . $fragment; | |
| } | |
| } | |
| $output[] = ' ' . str_repeat('*', $length) . '/'; | |
| return implode("\n", $output); | |
| } | |
| function compareSemanticVersion($a, $b) { | |
| $va = explode('.', $a); | |
| $vb = explode('.', $b); | |
| $max = 5; | |
| while ($max-- > 0) { | |
| $ca = current($va); | |
| $cb = current($vb); | |
| // FALSE means that we've run out of terms. If we're out of terms, | |
| // assume that the value is zero. This allows us to, for example, | |
| // meaningfully and correctly compare '3.0' and '3.0.0'. | |
| if ($ca === FALSE) $ca = 0; | |
| if ($cb === FALSE) $cb = 0; | |
| // Compare as integers rather than strings. | |
| $ca = (int) $ca; | |
| $cb = (int) $cb; | |
| if ($ca > $cb) { | |
| return 1; | |
| } elseif ($cb > $ca) { | |
| return -1; | |
| } | |
| next($va); | |
| next($vb); | |
| } | |
| return 0; | |
| } | |
| /** | |
| * This function answers the id of the Eclipse project that produces the bits | |
| * with the provided ClearlyDefined coordinates. | |
| * | |
| * FIXME This function doesn't belong here. | |
| */ | |
| function getEclipseProjectFor($id) { | |
| // FIXME We should draw on a data source of some kind rather than hardcoding. | |
| $map = array( | |
| '*/*/p2.p2-installable-unit/org.eclipse.rcp_root/*' => 'eclipse.platform', | |
| '*/*/p2.p2-installable-unit/org.eclipse.platform_root/*' => 'eclipse.platform', | |
| '*/*/p2.p2-installable-unit/org.eclipse.rcp.*/*' => 'eclipse.platform', | |
| '*/*/p2.p2-installable-unit/org.eclipse.platform.*/*' => 'eclipse.platform', | |
| '*/*/org.glassfish.grizzly/grizzly-npn*/2.0.0+' => 'ee4j.grizzly', | |
| '*/*/org.glassfish.grizzly/grizzly-thrift/1.3.15+' => 'ee4j.grizzly', | |
| '*/*/org.glassfish.grizzly/grizzly-memcached/1.3.19+' => 'ee4j.grizzly', | |
| '*/*/org.glassfish.grizzly/*/2.4.4+' => 'ee4j.grizzly', | |
| '*/*/org.glassfish.hk2*/*/2.6+' => 'ee4j.glassfish', | |
| '*/*/org.glassfish.mq/*/5.1.3+' => 'ee4j.openmq', | |
| '*/*/org.glassfish.tyrus*/*/1.15+' => 'ee4j.tyrus', | |
| '*/*/org.glassfish/jsonp-jaxrs/1.1.5+' => 'ee4j.jsonp', | |
| '*/*/org.glassfish.jersey*/*/2.28+' => 'ee4j.jersey' | |
| ); | |
| // This list is stable, I think. I believe that we can expand this out and | |
| // just include it in whatever data source we end up choose to use to represent | |
| // this information. | |
| $platform = array('platform', 'test', 'releng', 'webdav', 'externaltools', 'rcp', 'core', 'debug', 'help', 'ui', 'sdk', 'team', 'text', 'ltk', 'osgi', 'search', 'compare', 'update', 'ant', 'jface', 'swt', 'jsch', 'cvs', 'tomcat', 'target', 'ftp', 'license'); | |
| foreach ($platform as $fragment) { | |
| $map["*/*/p2.p2-installable-unit/org.eclipse.{$fragment}.*/*"] = 'eclipse.platform'; | |
| } | |
| $parts = explode('/', $id); | |
| foreach($map as $pattern => $project) { | |
| $bits = explode('/', $pattern); | |
| if (count($bits) < 5) continue; | |
| if (!fnmatch($bits[0], $parts[0])) continue; | |
| if (!fnmatch($bits[1], $parts[1])) continue; | |
| if (!fnmatch($bits[2], $parts[2])) continue; | |
| if (!fnmatch($bits[3], $parts[3])) continue; | |
| if ($bits[4] == '*') return $project; | |
| // If the version information ends with a plus (+), then we look for | |
| // matches that are the specified version and greater. Otherwise, | |
| // we look for straight up matches (exact isn't the right word here, | |
| // since the compareSemanticVersion function compares equivalence, so, e.g., | |
| // "1.0" and "1.0.0" are considered to match). | |
| // | |
| // Note that we don't do wildcard/glob matches within versions (i.e., | |
| // we do match '*' to mean "any version", but something like '1.*.8' isn't supported). | |
| if (preg_match('/^(?<version>.*)\+$/', $bits[4], $matches)) { | |
| if (compareSemanticVersion($matches['version'], $parts[4]) <= 0) return $project; | |
| } elseif (compareSemanticVersion($bits[4], $parts[4]) == 0) return $project; | |
| } | |
| return null; | |
| } | |
| ?> |