private string CreateServiceSlug(string service)
        {
            var  sb  = new StringBuilder();
            char sep = Path.DirectorySeparatorChar;

            if (!string.IsNullOrWhiteSpace(Namespace))
            {
                sb.AppendFormat("{0}{1}", Namespace, sep);
            }

            if (Uri.TryCreate(service, UriKind.Absolute, out Uri serviceUri))
            {
                sb.AppendFormat("{0}{1}", serviceUri.Scheme, sep);
                sb.AppendFormat("{0}", serviceUri.Host);

                if (!serviceUri.IsDefaultPort)
                {
                    sb.Append(PlatformUtils.IsWindows() ? '-' : ':');
                    sb.Append(serviceUri.Port);
                }

                sb.Append(serviceUri.AbsolutePath.Replace('/', sep));
            }
            else
            {
                sb.Append(service);
            }

            return(sb.ToString());
        }
        private static string GetGitPath(IEnvironment environment, IFileSystem fileSystem, ITrace trace)
        {
            const string unixGitName = "git";
            const string winGitName  = "git.exe";

            string gitExecPath;
            string programName = PlatformUtils.IsWindows() ? winGitName : unixGitName;

            // Use the GIT_EXEC_PATH environment variable if set
            if (environment.Variables.TryGetValue(Constants.EnvironmentVariables.GitExecutablePath,
                                                  out gitExecPath))
            {
                // If we're invoked from WSL we must locate the UNIX Git executable
                if (PlatformUtils.IsWindows() && WslUtils.IsWslPath(gitExecPath))
                {
                    programName = unixGitName;
                }

                string candidatePath = Path.Combine(gitExecPath, programName);
                if (fileSystem.FileExists(candidatePath))
                {
                    trace.WriteLine($"Using Git executable from GIT_EXEC_PATH: {candidatePath}");
                    return(candidatePath);
                }
            }

            // Otherwise try to locate the git(.exe) on the current PATH
            gitExecPath = environment.LocateExecutable(programName);
            trace.WriteLine($"Using PATH-located Git executable: {gitExecPath}");
            return(gitExecPath);
        }
        public EnvironmentVariables(IDictionary variables)
        {
            EnsureArgument.NotNull(variables, nameof(variables));

            // On Windows it is technically possible to get env vars which differ only by case
            // even though the general assumption is that they are case insensitive on Windows.
            // For example, some of the standard .NET types like System.Diagnostics.Process
            // will fail to start a process on Windows if given duplicate environment variables.
            // See this issue for more information: https://github.com/dotnet/corefx/issues/13146

            // If we're on the Windows platform we should de-duplicate by setting the string
            // comparer to OrdinalIgnoreCase.
            var comparer = PlatformUtils.IsWindows()
                ? StringComparer.OrdinalIgnoreCase
                : StringComparer.Ordinal;

            var dict = new Dictionary <string, string>(comparer);

            foreach (var key in variables.Keys)
            {
                if (key is string name && variables[key] is string value)
                {
                    dict[name] = value;
                }
            }

            _envars = dict;
        }
Пример #4
0
        public CommandContext()
        {
            Streams    = new StandardStreams();
            Trace      = new Trace();
            FileSystem = new FileSystem();

            var git    = new LibGit2();
            var envars = new EnvironmentVariables(Environment.GetEnvironmentVariables());

            Settings = new Settings(envars, git)
            {
                RepositoryPath = git.GetRepositoryPath(FileSystem.GetCurrentDirectory())
            };

            HttpClientFactory = new HttpClientFactory(Trace, Settings, Streams);

            if (PlatformUtils.IsWindows())
            {
                Terminal        = new WindowsTerminal(Trace);
                CredentialStore = WindowsCredentialManager.Open();
            }
            else if (PlatformUtils.IsPosix())
            {
                Terminal = new PosixTerminal(Trace);

                if (PlatformUtils.IsMacOS())
                {
                    CredentialStore = MacOSKeychain.Open();
                }
                else if (PlatformUtils.IsLinux())
                {
                    throw new NotImplementedException();
                }
            }
        }
Пример #5
0
        public CommandContext()
        {
            Streams = new StandardStreams();
            Trace   = new Trace();
            Git     = new LibGit2(Trace);

            if (PlatformUtils.IsWindows())
            {
                FileSystem      = new WindowsFileSystem();
                Environment     = new WindowsEnvironment(FileSystem);
                Terminal        = new WindowsTerminal(Trace);
                CredentialStore = WindowsCredentialManager.Open();
            }
            else if (PlatformUtils.IsPosix())
            {
                if (PlatformUtils.IsMacOS())
                {
                    FileSystem      = new MacOSFileSystem();
                    CredentialStore = MacOSKeychain.Open();
                }
                else if (PlatformUtils.IsLinux())
                {
                    throw new NotImplementedException();
                }

                Environment = new PosixEnvironment(FileSystem);
                Terminal    = new PosixTerminal(Trace);
            }

            string repoPath = Git.GetRepositoryPath(FileSystem.GetCurrentDirectory());

            Settings          = new Settings(Environment, Git, repoPath);
            HttpClientFactory = new HttpClientFactory(Trace, Settings, Streams);
        }
        private static void AppendAvailableStoreList(StringBuilder sb)
        {
            if (PlatformUtils.IsWindows())
            {
                sb.AppendFormat("  {1,-13} : Windows Credential Manager (not available over network/SSH sessions){0}",
                                Environment.NewLine, StoreNames.WindowsCredentialManager);

                sb.AppendFormat("  {1,-13} : DPAPI protected files{0}",
                                Environment.NewLine, StoreNames.Dpapi);
            }

            if (PlatformUtils.IsMacOS())
            {
                sb.AppendFormat("  {1,-13} : macOS Keychain{0}",
                                Environment.NewLine, StoreNames.MacOSKeychain);
            }

            if (PlatformUtils.IsLinux())
            {
                sb.AppendFormat("  {1,-13} : freedesktop.org Secret Service (requires graphical interface){0}",
                                Environment.NewLine, StoreNames.SecretService);
            }

            if (PlatformUtils.IsPosix())
            {
                sb.AppendFormat("  {1,-13} : GNU `pass` compatible credential storage (requires GPG and `pass`){0}",
                                Environment.NewLine, StoreNames.Gpg);
            }

            sb.AppendFormat("  {1,-13} : Git's in-memory credential cache{0}",
                            Environment.NewLine, StoreNames.Cache);

            sb.AppendFormat("  {1,-13} : store credentials in plain-text files (UNSECURE){0}",
                            Environment.NewLine, StoreNames.Plaintext);
        }
        Task IConfigurableComponent.UnconfigureAsync(
            IEnvironment environment, EnvironmentVariableTarget environmentTarget,
            IGit git, GitConfigurationLevel configurationLevel)
        {
            string helperKey        = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}";
            string gitConfigAppName = GetGitConfigAppName();

            IGitConfiguration targetConfig = git.GetConfiguration(configurationLevel);

            Context.Trace.WriteLine("Removing Git credential helper configuration...");

            // Clear any blank 'reset' entries
            targetConfig.UnsetAll(helperKey, Constants.RegexPatterns.Empty);

            // Clear GCM executable entries
            targetConfig.UnsetAll(helperKey, Regex.Escape(gitConfigAppName));

            // NOTE: We currently only update the PATH in Windows installations and leave removing the GCM executable
            //       on the PATH on other platform to their installers.
            // Remove GCM executable from the PATH
            if (PlatformUtils.IsWindows())
            {
                Context.Trace.WriteLine("Removing application from the PATH...");
                string directoryPath = Path.GetDirectoryName(_appPath);
                environment.RemoveDirectoryFromPath(directoryPath, environmentTarget);
            }

            return(Task.CompletedTask);
        }
        Task IConfigurableComponent.ConfigureAsync(
            IEnvironment environment, EnvironmentVariableTarget environmentTarget,
            IGit git, GitConfigurationLevel configurationLevel)
        {
            // NOTE: We currently only update the PATH in Windows installations and leave putting the GCM executable
            //       on the PATH on other platform to their installers.
            if (PlatformUtils.IsWindows())
            {
                string directoryPath = Path.GetDirectoryName(_appPath);
                if (!environment.IsDirectoryOnPath(directoryPath))
                {
                    Context.Trace.WriteLine("Adding application to PATH...");
                    environment.AddDirectoryToPath(directoryPath, environmentTarget);
                }
                else
                {
                    Context.Trace.WriteLine("Application is already on the PATH.");
                }
            }

            string helperKey        = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}";
            string gitConfigAppName = GetGitConfigAppName();

            IGitConfiguration targetConfig = git.GetConfiguration(configurationLevel);

            /*
             * We are looking for the following to be considered already set:
             *
             * [credential]
             *     ...                         # any number of helper entries
             *     helper =                    # an empty value to reset/clear any previous entries
             *     helper = {gitConfigAppName} # the expected executable value in the last position & directly following the empty value
             *
             */

            string[] currentValues = targetConfig.GetRegex(helperKey, Constants.RegexPatterns.Any).ToArray();
            if (currentValues.Length < 2 ||
                !string.IsNullOrWhiteSpace(currentValues[currentValues.Length - 2]) ||    // second to last entry is empty
                currentValues[currentValues.Length - 1] != gitConfigAppName)              // last entry is the expected executable
            {
                Context.Trace.WriteLine("Updating Git credential helper configuration...");

                // Clear any existing entries in the configuration.
                targetConfig.UnsetAll(helperKey, Constants.RegexPatterns.Any);

                // Add an empty value for `credential.helper`, which has the effect of clearing any helper value
                // from any lower-level Git configuration, then add a second value which is the actual executable path.
                targetConfig.SetValue(helperKey, string.Empty);
                targetConfig.ReplaceAll(helperKey, Constants.RegexPatterns.None, gitConfigAppName);
            }
            else
            {
                Context.Trace.WriteLine("Credential helper configuration is already set correctly.");
            }


            return(Task.CompletedTask);
        }
        private static string GetDefaultStore()
        {
            if (PlatformUtils.IsWindows())
            {
                return(StoreNames.WindowsCredentialManager);
            }

            if (PlatformUtils.IsMacOS())
            {
                return(StoreNames.MacOSKeychain);
            }

            // Other platforms have no default store
            return(null);
        }
        private string GetGitConfigAppPath()
        {
            string path = _appPath;

            // On Windows we must use UNIX style path separators
            if (PlatformUtils.IsWindows())
            {
                path = path.Replace('\\', '/');
            }

            // We must escape escape characters like ' ', '(', and ')'
            return(path
                   .Replace(" ", "\\ ")
                   .Replace("(", "\\(")
                   .Replace(")", "\\)"));;
        }
Пример #11
0
        private static string GetGitPath(IEnvironment environment, IFileSystem fileSystem)
        {
            string programName = PlatformUtils.IsWindows() ? "git.exe" : "git";

            // Use the GIT_EXEC_PATH environment variable if set
            if (environment.Variables.TryGetValue(Constants.EnvironmentVariables.GitExecutablePath,
                                                  out string gitExecPath))
            {
                string candidatePath = Path.Combine(gitExecPath, programName);
                if (fileSystem.FileExists(candidatePath))
                {
                    return(candidatePath);
                }
            }

            // Otherwise try to locate the git(.exe) on the current PATH
            return(environment.LocateExecutable(programName));
        }
Пример #12
0
        private static string GetApplicationPath()
        {
            Assembly entryAssembly = Assembly.GetExecutingAssembly();

            if (entryAssembly is null)
            {
                throw new InvalidOperationException();
            }

            string candidatePath = entryAssembly.Location;

            // Strip the .dll from assembly name on Mac and Linux
            if (!PlatformUtils.IsWindows() && Path.HasExtension(candidatePath))
            {
                return(Path.ChangeExtension(candidatePath, null));
            }

            return(candidatePath);
        }
        private void ValidateWindowsCredentialManager()
        {
            if (!PlatformUtils.IsWindows())
            {
                throw new Exception(
                          $"Can only use the '{StoreNames.WindowsCredentialManager}' credential store on Windows." +
                          Environment.NewLine +
                          $"See {Constants.HelpUrls.GcmCredentialStores} for more information."
                          );
            }

            if (!WindowsCredentialManager.CanPersist())
            {
                throw new Exception(
                          $"Unable to persist credentials with the '{StoreNames.WindowsCredentialManager}' credential store." +
                          Environment.NewLine +
                          $"See {Constants.HelpUrls.GcmCredentialStores} for more information."
                          );
            }
        }
Пример #14
0
        public override async Task <ICredential> GenerateCredentialAsync(InputArguments input)
        {
            ThrowIfDisposed();

            Uri uri = GetUriFromInput(input);

            // Determine the if the host supports Windows Integration Authentication (WIA)
            if (IsWindowsAuthAllowed)
            {
                if (PlatformUtils.IsWindows())
                {
                    Context.Trace.WriteLine($"Checking host '{uri.AbsoluteUri}' for Windows Integrated Authentication...");
                    bool isWiaSupported = await _winAuth.GetIsSupportedAsync(uri);

                    if (!isWiaSupported)
                    {
                        Context.Trace.WriteLine("Host does not support WIA.");
                    }
                    else
                    {
                        Context.Trace.WriteLine("Host supports WIA - generating empty credential...");

                        // WIA is signaled to Git using an empty username/password
                        return(new GitCredential(string.Empty, string.Empty));
                    }
                }
                else
                {
                    string osType = PlatformUtils.GetPlatformInformation().OperatingSystemType;
                    Context.Trace.WriteLine($"Skipping check for Windows Integrated Authentication on {osType}.");
                }
            }
            else
            {
                Context.Trace.WriteLine("Windows Integrated Authentication detection has been disabled.");
            }

            Context.Trace.WriteLine("Prompting for basic credentials...");
            return(_basicAuth.GetCredentials(uri.AbsoluteUri, uri.UserInfo));
        }
        private void ValidateDpapi(out string storeRoot)
        {
            if (!PlatformUtils.IsWindows())
            {
                throw new Exception(
                          $"Can only use the '{StoreNames.Dpapi}' credential store on Windows." +
                          Environment.NewLine +
                          $"See {Constants.HelpUrls.GcmCredentialStores} for more information."
                          );
            }

            // Check for a redirected credential store location
            if (!_context.Settings.TryGetSetting(
                    Constants.EnvironmentVariables.GcmDpapiStorePath,
                    Constants.GitConfiguration.Credential.SectionName,
                    Constants.GitConfiguration.Credential.DpapiStorePath,
                    out storeRoot))
            {
                // Use default store root at ~/.gcm/dpapi_store
                storeRoot = Path.Combine(_context.FileSystem.UserDataDirectoryPath, "dpapi_store");
            }
        }
Пример #16
0
        public CommandContext()
        {
            Streams = new StandardStreams();
            Trace   = new Trace();

            if (PlatformUtils.IsWindows())
            {
                FileSystem     = new WindowsFileSystem();
                SessionManager = new WindowsSessionManager();
                SystemPrompts  = new WindowsSystemPrompts();
                Environment    = new WindowsEnvironment(FileSystem);
                Terminal       = new WindowsTerminal(Trace);
                string gitPath = GetGitPath(Environment, FileSystem);
                Git = new GitProcess(
                    Trace,
                    gitPath,
                    FileSystem.GetCurrentDirectory()
                    );
                Settings        = new Settings(Environment, Git);
                CredentialStore = new WindowsCredentialManager(Settings.CredentialNamespace);
            }
            else if (PlatformUtils.IsMacOS())
            {
                FileSystem     = new MacOSFileSystem();
                SessionManager = new MacOSSessionManager();
                SystemPrompts  = new MacOSSystemPrompts();
                Environment    = new PosixEnvironment(FileSystem);
                Terminal       = new PosixTerminal(Trace);
                string gitPath = GetGitPath(Environment, FileSystem);
                Git = new GitProcess(
                    Trace,
                    gitPath,
                    FileSystem.GetCurrentDirectory()
                    );
                Settings        = new Settings(Environment, Git);
                CredentialStore = new MacOSKeychain(Settings.CredentialNamespace);
            }
            else if (PlatformUtils.IsLinux())
            {
                FileSystem = new LinuxFileSystem();
                // TODO: support more than just 'Posix' or X11
                SessionManager = new PosixSessionManager();
                SystemPrompts  = new LinuxSystemPrompts();
                Environment    = new PosixEnvironment(FileSystem);
                Terminal       = new PosixTerminal(Trace);
                string gitPath = GetGitPath(Environment, FileSystem);
                Git = new GitProcess(
                    Trace,
                    gitPath,
                    FileSystem.GetCurrentDirectory()
                    );
                Settings = new Settings(Environment, Git);
                IGpg gpg = new Gpg(
                    Environment.LocateExecutable("gpg"),
                    SessionManager
                    );
                CredentialStore = new LinuxCredentialStore(FileSystem, Settings, SessionManager, gpg, Environment);
            }
            else
            {
                throw new PlatformNotSupportedException();
            }

            HttpClientFactory = new HttpClientFactory(Trace, Settings, Streams);

            // Set the parent window handle/ID
            SystemPrompts.ParentWindowId = Settings.ParentWindowId;
        }
        public CommandContext(string appPath)
        {
            EnsureArgument.NotNullOrWhiteSpace(appPath, nameof(appPath));

            ApplicationPath = appPath;
            Streams         = new StandardStreams();
            Trace           = new Trace();

            if (PlatformUtils.IsWindows())
            {
                FileSystem     = new WindowsFileSystem();
                SessionManager = new WindowsSessionManager();
                SystemPrompts  = new WindowsSystemPrompts();
                Environment    = new WindowsEnvironment(FileSystem);
                Terminal       = new WindowsTerminal(Trace);
                string gitPath = GetGitPath(Environment, FileSystem, Trace);
                Git = new GitProcess(
                    Trace,
                    Environment,
                    gitPath,
                    FileSystem.GetCurrentDirectory()
                    );
                Settings = new WindowsSettings(Environment, Git, Trace);
            }
            else if (PlatformUtils.IsMacOS())
            {
                FileSystem     = new MacOSFileSystem();
                SessionManager = new MacOSSessionManager();
                SystemPrompts  = new MacOSSystemPrompts();
                Environment    = new PosixEnvironment(FileSystem);
                Terminal       = new MacOSTerminal(Trace);
                string gitPath = GetGitPath(Environment, FileSystem, Trace);
                Git = new GitProcess(
                    Trace,
                    Environment,
                    gitPath,
                    FileSystem.GetCurrentDirectory()
                    );
                Settings = new Settings(Environment, Git);
            }
            else if (PlatformUtils.IsLinux())
            {
                FileSystem = new LinuxFileSystem();
                // TODO: support more than just 'Posix' or X11
                SessionManager = new PosixSessionManager();
                SystemPrompts  = new LinuxSystemPrompts();
                Environment    = new PosixEnvironment(FileSystem);
                Terminal       = new LinuxTerminal(Trace);
                string gitPath = GetGitPath(Environment, FileSystem, Trace);
                Git = new GitProcess(
                    Trace,
                    Environment,
                    gitPath,
                    FileSystem.GetCurrentDirectory()
                    );
                Settings = new Settings(Environment, Git);
            }
            else
            {
                throw new PlatformNotSupportedException();
            }

            HttpClientFactory = new HttpClientFactory(FileSystem, Trace, Settings, Streams);
            CredentialStore   = new CredentialStore(this);

            // Set the parent window handle/ID
            SystemPrompts.ParentWindowId = Settings.ParentWindowId;
        }