@@ -237,6 +237,66 @@ public void CanCloneFromBBWithCredentials(string url, string user, string pass,
237237 }
238238 }
239239
240+ [ SkippableTheory ]
241+ [ InlineData ( "https://github.com/libgit2/TestGitRepository.git" , "github.com" , typeof ( CertificateX509 ) ) ]
242+ [ InlineData ( "git@github.com:libgit2/TestGitRepository.git" , "github.com" , typeof ( CertificateSsh ) ) ]
243+ public void CanInspectCertificateOnClone ( string url , string hostname , Type certType )
244+ {
245+ var scd = BuildSelfCleaningDirectory ( ) ;
246+
247+ InconclusiveIf (
248+ ( ) =>
249+ certType == typeof ( CertificateSsh ) && ! GlobalSettings . Version . Features . HasFlag ( BuiltInFeatures . Ssh ) ,
250+ "SSH not supported" ) ;
251+
252+ bool wasCalled = false ;
253+ bool checksHappy = false ;
254+
255+ var options = new CloneOptions {
256+ CertificateCheck = ( cert , valid , host ) => {
257+ wasCalled = true ;
258+
259+ Assert . Equal ( hostname , host ) ;
260+ Assert . Equal ( certType , cert . GetType ( ) ) ;
261+
262+ if ( certType == typeof ( CertificateX509 ) ) {
263+ Assert . True ( valid ) ;
264+ var x509 = ( ( CertificateX509 ) cert ) . Certificate ;
265+ // we get a string with the different fields instead of a structure, so...
266+ Assert . True ( x509 . Subject . Contains ( "CN=github.com," ) ) ;
267+ checksHappy = true ;
268+ return false ;
269+ }
270+
271+ if ( certType == typeof ( CertificateSsh ) ) {
272+ var hostkey = ( CertificateSsh ) cert ;
273+ Assert . True ( hostkey . HasMD5 ) ;
274+ /*
275+ * Once you've connected and thus your ssh has stored the hostkey,
276+ * you can get the hostkey for a host with
277+ *
278+ * ssh-keygen -F github.com -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':'
279+ *
280+ * though GitHub's hostkey won't change anytime soon.
281+ */
282+ Assert . Equal ( "1627aca576282d36631b564debdfa648" ,
283+ BitConverter . ToString ( hostkey . HashMD5 ) . ToLower ( ) . Replace ( "-" , "" ) ) ;
284+ checksHappy = true ;
285+ return false ;
286+ }
287+
288+ return false ;
289+ } ,
290+ } ;
291+
292+ Assert . Throws < UserCancelledException > ( ( ) =>
293+ Repository . Clone ( url , scd . DirectoryPath , options )
294+ ) ;
295+
296+ Assert . True ( wasCalled ) ;
297+ Assert . True ( checksHappy ) ;
298+ }
299+
240300 [ Fact ]
241301 public void CloningAnUrlWithoutPathThrows ( )
242302 {
0 commit comments