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 void ValidateGpgPass(out string storeRoot, out string execPath) { if (!PlatformUtils.IsPosix()) { throw new Exception( $"Can only use the '{StoreNames.Gpg}' credential store on POSIX systems." + Environment.NewLine + $"See {Constants.HelpUrls.GcmCredentialStores} for more information." ); } execPath = GetGpgPath(); // If we are in a headless environment, and don't have the GPG_TTY or SSH_TTY // variables set, then error - we need a TTY device path for pin-entry to work headless. if (!_context.SessionManager.IsDesktopSession && !_context.Environment.Variables.ContainsKey("GPG_TTY") && !_context.Environment.Variables.ContainsKey("SSH_TTY")) { throw new Exception( "GPG_TTY is not set; add `export GPG_TTY=$(tty)` to your profile." + Environment.NewLine + $"See {Constants.HelpUrls.GcmCredentialStores} for more information." ); } // Check for a redirected pass store location if (!_context.Settings.TryGetSetting( GpgPassCredentialStore.PasswordStoreDirEnvar, null, null, out storeRoot)) { // Use default store root at ~/.password-store storeRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".password-store"); } // Check we have a GPG ID to sign credential files with string gpgIdFile = Path.Combine(storeRoot, ".gpg-id"); if (!_context.FileSystem.FileExists(gpgIdFile)) { throw new Exception( $"Password store has not been initialized at '{storeRoot}'; run `pass init <gpg-id>` to initialize the store." + Environment.NewLine + $"See {Constants.HelpUrls.GcmCredentialStores} for more information." ); } }
private string GetGitConfigAppPath() { string path = Context.ApplicationPath; // 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(")", "\\)"));; }
protected override async Task <int> RunInternalAsync(string[] args) { var rootCommand = new RootCommand(); var diagnoseCommand = new DiagnoseCommand(Context); // Add standard commands rootCommand.AddCommand(new GetCommand(Context, _providerRegistry)); rootCommand.AddCommand(new StoreCommand(Context, _providerRegistry)); rootCommand.AddCommand(new EraseCommand(Context, _providerRegistry)); rootCommand.AddCommand(new ConfigureCommand(Context, _configurationService)); rootCommand.AddCommand(new UnconfigureCommand(Context, _configurationService)); rootCommand.AddCommand(diagnoseCommand); // Add any custom provider commands foreach (ProviderCommand providerCommand in _providerCommands) { rootCommand.AddCommand(providerCommand); } // Add any custom provider diagnostic tests foreach (IDiagnostic providerDiagnostic in _diagnostics) { diagnoseCommand.AddDiagnostic(providerDiagnostic); } // Trace the current version, OS, runtime, and program arguments PlatformInformation info = PlatformUtils.GetPlatformInformation(); Context.Trace.WriteLine($"Version: {Constants.GcmVersion}"); Context.Trace.WriteLine($"Runtime: {info.ClrVersion}"); Context.Trace.WriteLine($"Platform: {info.OperatingSystemType} ({info.CpuArchitecture})"); Context.Trace.WriteLine($"OSVersion: {info.OperatingSystemVersion}"); Context.Trace.WriteLine($"AppPath: {Context.ApplicationPath}"); Context.Trace.WriteLine($"Arguments: {string.Join(" ", args)}"); var parser = new CommandLineBuilder(rootCommand) .UseDefaults() .UseExceptionHandler(OnException) .Build(); return(await parser.InvokeAsync(args)); }
private void ValidateSecretService() { if (!PlatformUtils.IsLinux()) { throw new Exception( $"Can only use the '{StoreNames.SecretService}' credential store on Linux." + Environment.NewLine + $"See {Constants.HelpUrls.GcmCredentialStores} for more information." ); } if (!_context.SessionManager.IsDesktopSession) { throw new Exception( $"Cannot use the '{StoreNames.SecretService}' credential backing store without a graphical interface present." + Environment.NewLine + $"See {Constants.HelpUrls.GcmCredentialStores} for more information." ); } }
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." ); } }
public override async Task <ICredential> GenerateCredentialAsync(InputArguments input) { ThrowIfDisposed(); Uri uri = input.GetRemoteUri(); // 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, input.UserName)); }
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"); } }
/// <summary> /// Ensure the store root directory exists. If it does not, create a new directory with /// permissions that only permit the owner to read/write/execute. Permissions on an existing /// directory are not modified. /// </summary> private void EnsureStoreRoot() { if (FileSystem.DirectoryExists(StoreRoot)) { // Don't touch the permissions on the existing directory return; } FileSystem.CreateDirectory(StoreRoot); // We only set file system permissions on POSIX platforms if (!PlatformUtils.IsPosix()) { return; } // Set store root permissions such that only the owner can read/write/execute var mode = Interop.Posix.Native.NativeFileMode.S_IRUSR | Interop.Posix.Native.NativeFileMode.S_IWUSR | Interop.Posix.Native.NativeFileMode.S_IXUSR; // Ignore the return code.. this is a best effort only Interop.Posix.Native.Stat.chmod(StoreRoot, mode); }
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; }
public static void OpenDefaultBrowser(IEnvironment environment, Uri uri) { if (!uri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) && !uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("Can only open HTTP/HTTPS URIs", nameof(uri)); } string url = uri.ToString(); ProcessStartInfo psi = null; if (PlatformUtils.IsLinux()) { // On Linux, 'shell execute' utilities like xdg-open launch a process without // detaching from the standard in/out descriptors. Some applications (like // Chromium) write messages to stdout, which is currently hooked up and being // consumed by Git, and cause errors. // // Sadly, the Framework does not allow us to redirect standard streams if we // set ProcessStartInfo::UseShellExecute = true, so we must manually launch // these utilities and redirect the standard streams manually. // // We try and use the same 'shell execute' utilities as the Framework does, // searching for them in the same order until we find one. // // One additional 'shell execute' utility we also attempt to use is `wslview` // that is commonly found on WSL (Windows Subsystem for Linux) distributions that // opens the browser on the Windows host. foreach (string shellExec in new[] { "xdg-open", "gnome-open", "kfmclient", "wslview" }) { if (environment.TryLocateExecutable(shellExec, out string shellExecPath)) { psi = new ProcessStartInfo(shellExecPath, url) { RedirectStandardOutput = true, RedirectStandardError = true }; // We found a way to open the URI; stop searching! break; } } if (psi is null) { throw new Exception("Failed to locate a utility to launch the default web browser."); } } else { // On Windows and macOS, `ShellExecute` and `/usr/bin/open` disconnect the child process // from our standard in/out streams, so we can just use the Framework to do this. psi = new ProcessStartInfo(url) { UseShellExecute = true }; } Process.Start(psi); }