/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/; const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/; const AuthorityMatcher = /^([^@]+@)?([^:]+)(:\d+)?$/; const SecondLevelDomainMatcher = /([^@:.]+\.[^@:.]+)(:\d+)?$/; const RemoteMatcher = /^\s*url\s*=\s*(.+\S)\s*$/mg; const AnyButDot = /[^.]/g; export const AllowedSecondLevelDomains = [ 'github.com', 'bitbucket.org', 'visualstudio.com', 'gitlab.com', 'heroku.com', 'azurewebsites.net', 'ibm.com', 'amazon.com', 'amazonaws.com', 'cloudapp.net', 'rhcloud.com', 'google.com', 'azure.com' ]; function stripLowLevelDomains(domain: string): string | null { const match = domain.match(SecondLevelDomainMatcher); return match ? match[1] : null; } function extractDomain(url: string): string | null { if (url.indexOf('://') === -1) { const match = url.match(SshProtocolMatcher); if (match) { return stripLowLevelDomains(match[2]); } else { return null; } } try { const uri = URI.parse(url); if (uri.authority) { return stripLowLevelDomains(uri.authority); } } catch (e) { // ignore invalid URIs } return null; } export function getDomainsOfRemotes(text: string, allowedDomains: readonly string[]): string[] { const domains = new Set(); let match: RegExpExecArray | null; while (match = RemoteMatcher.exec(text)) { const domain = extractDomain(match[1]); if (domain) { domains.add(domain); } } const allowedDomainsSet = new Set(allowedDomains); return Array.from(domains) .map(key => allowedDomainsSet.has(key) ? key : key.replace(AnyButDot, 'a')); } function stripPort(authority: string): string | null { const match = authority.match(AuthorityMatcher); return match ? match[2] : null; } function normalizeRemote(host: string | null, path: string, stripEndingDotGit: boolean): string | null { if (host && path) { if (stripEndingDotGit && path.endsWith('.git')) { path = path.substr(0, path.length - 4); } return (path.indexOf('/') === 0) ? `${host}${path}` : `${host}/${path}`; } return null; } function extractRemote(url: string, stripEndingDotGit: boolean): string | null { if (url.indexOf('://') === -1) { const match = url.match(SshUrlMatcher); if (match) { return normalizeRemote(match[2], match[3], stripEndingDotGit); } } try { const uri = URI.parse(url); if (uri.authority) { return normalizeRemote(stripPort(uri.authority), uri.path, stripEndingDotGit); } } catch (e) { // ignore invalid URIs } return null; } export function getRemotes(text: string, stripEndingDotGit: boolean = false): string[] { const remotes: string[] = []; let match: RegExpExecArray | null; while (match = RemoteMatcher.exec(text)) { const remote = extractRemote(match[1], stripEndingDotGit); if (remote) { remotes.push(remote); } } return remotes; }