| <?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/jakarta.json/*' => 'ee4j.jsonp', |
| |
| '*/*/org.eclipse.parsson/*/*' => 'ee4j.parsson', |
| |
| '*/*/org.glassfish/jsonp-jaxrs/1.1.5+' => 'ee4j.jsonp', |
| |
| '*/*/org.glassfish.jersey*/*/2.28+' => 'ee4j.jersey', |
| |
| '*/*/jakarta.activation/*/*' => 'ee4j.jaf', |
| '*/*/jakarta.annotation/*/*' => 'ee4j.ca', |
| '*/*/jakarta.servlet/*/*' => 'ee4j.servlet', |
| '*/*/jakarta.ws.rs/*/*' => 'ee4j.jaxrs', |
| '*/*/jakarta.xml.bind/*/*' => 'ee4j.jaxb', |
| |
| '*/*/com.sun.activation/jakarta.activation/*' => 'ee4j.jaf', |
| '*/*/org.eclipse.aether/*/*' => 'technology.aether', |
| '*/*/org.eclipse.dash/*/*' => 'technology.dash', |
| '*/*/org.eclipse.sisu/*/*' => 'technology.sisu', |
| |
| '*/*/@theia/*/*' => 'ecd.theia' |
| |
| ); |
| |
| // 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; |
| } |
| ?> |