Repository navigation
Expand file tree
/
Copy pathGpg.cs
More file actions
111 lines (93 loc) · 3.88 KB
/
Copy pathGpg.cs
File metadata and controls
111 lines (93 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Diagnostics;
namespace GitCredentialManager
{
public interface IGpg
{
string DecryptFile(string path);
void EncryptFile(string path, string gpgId, string contents);
}
public class Gpg : IGpg
{
private readonly string _gpgPath;
private readonly ISessionManager _sessionManager;
private readonly IProcessManager _processManager;
public Gpg(string gpgPath, ISessionManager sessionManager, IProcessManager processManager)
{
EnsureArgument.NotNullOrWhiteSpace(gpgPath, nameof(gpgPath));
EnsureArgument.NotNull(sessionManager, nameof(sessionManager));
_gpgPath = gpgPath;
_sessionManager = sessionManager;
_processManager = processManager;
}
public string DecryptFile(string path)
{
var psi = new ProcessStartInfo(_gpgPath, $"--batch --decrypt \"{path}\"")
{
UseShellExecute = false,
RedirectStandardOutput = true,
// Suppress verbose decryption messages
// Ok to redirect stderr for non-Git-related processes
RedirectStandardError = true,
};
PrepareEnvironment(psi);
using (var gpg = _processManager.CreateProcess(psi, Trace2ProcessClass.Other))
{
if (!gpg.Start())
{
throw new Exception("Failed to start gpg.");
}
gpg.WaitForExit();
if (gpg.ExitCode != 0)
{
string stdout = gpg.StandardOutput.ReadToEnd();
string stderr = gpg.StandardError.ReadToEnd();
var format = "Failed to decrypt file '{0}' with gpg. exit={1}, out={2}, err={3}";
var message = string.Format(format, path, gpg.ExitCode, stdout, stderr);
throw new Exception(message);
}
return gpg.StandardOutput.ReadToEnd();
}
}
public void EncryptFile(string path, string gpgId, string contents)
{
var psi = new ProcessStartInfo(_gpgPath, $"--encrypt --batch --recipient \"{gpgId}\" --output \"{path}\"")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true, // Ok to redirect stderr for non-git-related processes
};
PrepareEnvironment(psi);
using (var gpg = _processManager.CreateProcess(psi, Trace2ProcessClass.Other))
{
if (!gpg.Start())
{
throw new Exception("Failed to start gpg.");
}
gpg.StandardInput.Write(contents);
gpg.StandardInput.Close();
gpg.WaitForExit();
if (gpg.ExitCode != 0)
{
string stdout = gpg.StandardOutput.ReadToEnd();
string stderr = gpg.StandardError.ReadToEnd();
var format = "Failed to encrypt file '{0}' with gpg. exit={1}, out={2}, err={3}";
var message = string.Format(format, path, gpg.ExitCode, stdout, stderr);
throw new Exception(message);
}
}
}
private void PrepareEnvironment(ProcessStartInfo psi)
{
// If we're in a headless environment over SSH, and we don't have a GPG_TTY
// explicitly set, use the SSH_TTY variable for our GPG_TTY.
if (!_sessionManager.IsDesktopSession &&
!psi.Environment.ContainsKey("GPG_TTY") &&
psi.Environment.ContainsKey("SSH_TTY"))
{
psi.Environment["GPG_TTY"] = psi.Environment["SSH_TTY"];
}
}
}
}