forked from gdevic/GitForce
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ClassPutty.cs
164 lines (145 loc) · 6.37 KB
/
ClassPutty.cs
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace GitForce
{
/// <summary>
/// Manage PuTTY, PLink and PuttyGen utilities.
/// This class should be instantiated on Windows OS only.
/// </summary>
public class ClassPutty
{
private readonly string _pathPageant;
private readonly string _pathPlink;
private readonly string _pathPuttyGen;
private Process _procPageant;
/// <summary>
/// Constructor class function, create executables in temp space
/// </summary>
public ClassPutty()
{
_pathPageant = ClassUtils.WriteResourceToFile(Path.GetTempPath(), "pageant.exe", Properties.Resources.pageant);
_pathPlink = ClassUtils.WriteResourceToFile(Path.GetTempPath(), "plink.exe", Properties.Resources.plink);
_pathPuttyGen = ClassUtils.WriteResourceToFile(Path.GetTempPath(), "puttygen.exe", Properties.Resources.puttygen);
ClassUtils.AddEnvar("PLINK_PROTOCOL", "ssh");
ClassUtils.AddEnvar("GIT_SSH", _pathPlink);
// Run the daemon process, update keys
RunPageantUpdateKeys();
}
/// <summary>
/// Destructor for the class make sure the executable resources are properly disposed of
/// </summary>
~ClassPutty()
{
// No real harm done if we fail to remove these temp files. Next time GitForce is
// run we will reuse the same file names, so the junk will not grow in the temp folder.
try
{
// Dont attempt to stop/remove Pageant if the user wanted to leave it running
if (Properties.Settings.Default.leavePageant == false)
{
if (_procPageant != null)
{
if (!_procPageant.HasExited)
{
// Send a notification to Pageant to close
IntPtr winHandle = NativeMethods.FindWindow("Pageant", null);
NativeMethods.SendMessage(winHandle, NativeMethods.WM_COMMAND, NativeMethods.WM_CLOSE, 0);
}
//File.Delete(_pathPageant);
}
}
// Note: We leave these files in to allow secondary application instances to co-exist
//File.Delete(_pathPlink);
//File.Delete(_pathPuttyGen);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Run the PuTTYgen process and wait until it exits.
/// </summary>
public void RunPuTTYgen()
{
Process.Start(_pathPuttyGen).WaitForExit();
}
/// <summary>
/// Runs the pageant daemon process and loads keys
/// </summary>
public void RunPageantUpdateKeys()
{
// Load list of keys and passphrases to send to the pageant process
List<string> keys = Properties.Settings.Default.PuTTYKeys.
Split((",").ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
List<string> pfs = GetPassPhrases();
StringBuilder args = new StringBuilder();
// Passphrases must be specified first in the list of arguments
foreach (string s in pfs)
args.Append(" -x \"" + s + "\"");
// Followed by the list of keys to load
foreach (string s in keys)
args.Append(" \"" + s + "\"");
// Run the pageant process if we have any (new) keys or phrases to import,
// or if the pageant process is not running
bool isPageantRunning = Process.GetProcesses().Any(proc => proc.ProcessName == "pageant");
if (args.Length > 0 || isPageantRunning==false)
{
_procPageant = new Process();
_procPageant.StartInfo.FileName = _pathPageant;
_procPageant.StartInfo.Arguments = args.ToString();
// TODO: Handle unsuccessful process start
_procPageant.Start();
}
}
/// <summary>
/// Returns the list of passphrases in plaintext format
/// </summary>
public List<string> GetPassPhrases()
{
// Base-64 encoded strings, zero-delimited, are read from application settings
List<string> pfs = Properties.Settings.Default.PuTTYPf.
Split(("\0").ToCharArray(),
StringSplitOptions.RemoveEmptyEntries).
ToList();
// Select each string and tramsform it from Base-64 to plaintext
pfs = pfs.Select(
s => Encoding.ASCII.GetString(
Convert.FromBase64String(s))).
ToList();
return pfs;
}
/// <summary>
/// Saves the list of passphrases into application properties
/// </summary>
public void SetPassPhrases(List<string> pfs)
{
// Convert each passphrase into Base-64 encoded string
pfs = pfs.Select(
s => Convert.ToBase64String(
Encoding.ASCII.GetBytes(s))).
ToList();
Properties.Settings.Default.PuTTYPf = String.Join("\0", pfs.ToArray());
}
/// <summary>
/// Initializes SSH connection by running the PLINK using the specified
/// connection parameters. This function blocks until the PLINK returns.
/// </summary>
public void ImportRemoteSshKey(ClassUrl.Url url)
{
// Build the arguments to the PLINK process: port number, user and the host
// Use the default SSH values if the url did not provide them
string args = " -P " + (url.Port > 0 ? url.Port.ToString() : "22") +
" -l " + (string.IsNullOrEmpty(url.User) ? "anonymous" : url.User) +
" " + url.Host;
// plink does everything through its stderr stream
ExecResult result = Exec.Run(_pathPlink, args);
App.PrintLogMessage(result.stderr);
}
}
}