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); }
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." ); } }
/// <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); }