Skip to content

Commit

Permalink
commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vinokurig committed Oct 26, 2023
1 parent f76061a commit f171640
Showing 1 changed file with 88 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static java.util.regex.Pattern.compile;
import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException;
import static org.eclipse.che.api.factory.server.github.GithubApiClient.GITHUB_SAAS_ENDPOINT;
Expand Down Expand Up @@ -46,14 +47,16 @@
import org.slf4j.LoggerFactory;

/**
* Parser of String Github URLs and provide {@link GithubUrl} objects.
* Parser of String GitHub URLs and provide {@link GithubUrl} objects.
*
* @author Florent Benoit
*/
@Singleton
public class GithubURLParser {

private static final Logger LOG = LoggerFactory.getLogger(GithubURLParser.class);

private static final String OAUTH_PROVIDER_NAME = "github";
private final PersonalAccessTokenManager tokenManager;
private final DevfileFilenamesProvider devfileFilenamesProvider;
private final GithubApiClient apiClient;
Expand All @@ -64,7 +67,10 @@ public class GithubURLParser {
*/
private final Pattern githubPattern;

private final String githubPatternTemplate =
"^%s/(?<repoUser>[^/]+)/(?<repoName>[^/]++)((/)|(?:/tree/(?<branchName>.++))|(/pull/(?<pullRequestId>\\d++)))?$";
private final Pattern githubSSHPattern;
private final String githubSSHPatternTemplate = "^git@%s:(?<repoUser>.*)/(?<repoName>.*)$";

private final boolean disableSubdomainIsolation;

Expand Down Expand Up @@ -99,32 +105,105 @@ public GithubURLParser(
String endpoint =
isNullOrEmpty(oauthEndpoint) ? GITHUB_SAAS_ENDPOINT : trimEnd(oauthEndpoint, '/');

this.githubPattern =
compile(
format(
"^%s/(?<repoUser>[^/]+)/(?<repoName>[^/]++)((/)|(?:/tree/(?<branchName>.++))|(/pull/(?<pullRequestId>\\d++)))?$",
endpoint));
this.githubPattern = compile(format(githubPatternTemplate, endpoint));
this.githubSSHPattern =
compile(format("^git@%s:(?<repoUser>.*)/(?<repoName>.*)$", URI.create(endpoint).getHost()));
compile(format(githubSSHPatternTemplate, URI.create(endpoint).getHost()));
}

public boolean isValid(@NotNull String url) {
String trimmedUrl = trimEnd(url, '/');
return githubPattern.matcher(trimmedUrl).matches()
|| githubSSHPattern.matcher(trimmedUrl).matches();
|| githubSSHPattern.matcher(trimmedUrl).matches()
|| isUserTokenPresent(trimmedUrl)
|| isApiRequestRelevant(trimmedUrl);
}

private boolean isUserTokenPresent(String repositoryUrl) {
Optional<String> serverUrlOptional = getServerUrl(repositoryUrl);
if (serverUrlOptional.isPresent()) {
String serverUrl = serverUrlOptional.get();
try {
Optional<PersonalAccessToken> token =
tokenManager.get(EnvironmentContext.getCurrent().getSubject(), serverUrl);
if (token.isPresent()) {
PersonalAccessToken accessToken = token.get();
return accessToken.getScmTokenName().equals(OAUTH_PROVIDER_NAME);
}
} catch (ScmConfigurationPersistenceException
| ScmUnauthorizedException
| ScmCommunicationException exception) {
return false;
}
}
return false;
}

private boolean isApiRequestRelevant(String repositoryUrl) {
Optional<String> serverUrlOptional = getServerUrl(repositoryUrl);
if (serverUrlOptional.isPresent()) {
GithubApiClient GithubApiClient = new GithubApiClient(serverUrlOptional.get());
try {
// If the user request catches the unauthorised error, it means that the provided url
// belongs to GitHub.
GithubApiClient.getUser("");
} catch (ScmCommunicationException e) {
return e.getStatusCode() == HTTP_UNAUTHORIZED;
} catch (ScmItemNotFoundException | ScmBadRequestException | IllegalArgumentException e) {
return false;
}
}
return false;
}

private Optional<String> getServerUrl(String repositoryUrl) {
if (repositoryUrl.startsWith("git@")) {
String substring = repositoryUrl.substring(4);
return Optional.of("https://" + substring.substring(0, substring.indexOf(":")));
}
Matcher serverUrlMatcher = compile("[^/|:]/").matcher(repositoryUrl);
if (serverUrlMatcher.find()) {
return Optional.of(
repositoryUrl.substring(0, repositoryUrl.indexOf(serverUrlMatcher.group()) + 1));
}
return Optional.empty();
}

public GithubUrl parseWithoutAuthentication(String url) throws ApiException {
return parse(trimEnd(url, '/'), false);
}

private Optional<Matcher> getPatternMatcherByUrl(String url) {
URI uri =
URI.create(
url.matches(format(githubSSHPatternTemplate, ".*"))
? "ssh://" + url.replace(":", "/")
: url);
String scheme = uri.getScheme();
String host = uri.getHost();
Matcher matcher = compile(format(githubPatternTemplate, scheme + "://" + host)).matcher(url);
if (matcher.matches()) {
return Optional.of(matcher);
} else {
matcher = compile(format(githubSSHPatternTemplate, host)).matcher(url);
return matcher.matches() ? Optional.of(matcher) : Optional.empty();
}
}

public GithubUrl parse(String url) throws ApiException {
return parse(trimEnd(url, '/'), true);
}

private GithubUrl parse(String url, boolean authenticationRequired) throws ApiException {
Matcher matcher;
boolean isHTTPSUrl = githubPattern.matcher(url).matches();
Matcher matcher = isHTTPSUrl ? githubPattern.matcher(url) : githubSSHPattern.matcher(url);
if (isHTTPSUrl) {
matcher = githubPattern.matcher(url);
} else if (githubSSHPattern.matcher(url).matches()) {
matcher = githubSSHPattern.matcher(url);
} else {
matcher = getPatternMatcherByUrl(url).orElseThrow(IllegalArgumentException::new);
}

if (!matcher.matches()) {
throw new IllegalArgumentException(
format("The given url %s is not a valid github URL. ", url));
Expand Down

0 comments on commit f171640

Please sign in to comment.