22// The .NET Foundation licenses this file to you under the MIT license.
33// See the LICENSE file in the project root for more information.
44
5+ using DevProxy . Abstractions . Utils ;
56using DevProxy . Proxy ;
67using System . CommandLine ;
8+ using System . CommandLine . Invocation ;
79using System . CommandLine . Parsing ;
10+ using System . Diagnostics ;
11+ using Titanium . Web . Proxy . Helpers ;
812
913namespace DevProxy . Commands ;
1014
1115sealed class CertCommand : Command
1216{
1317 private readonly ILogger _logger ;
18+ private readonly Option < bool > _forceOption = new ( [ "--force" , "-f" ] , "Don't prompt for confirmation when removing the certificate" ) ;
1419
1520 public CertCommand ( ILogger < CertCommand > logger ) :
1621 base ( "cert" , "Manage the Dev Proxy certificate" )
@@ -25,9 +30,14 @@ private void ConfigureCommand()
2530 var certEnsureCommand = new Command ( "ensure" , "Ensure certificates are setup (creates root if required). Also makes root certificate trusted." ) ;
2631 certEnsureCommand . SetHandler ( EnsureCertAsync ) ;
2732
33+ var certRemoveCommand = new Command ( "remove" , "Remove the certificate from Root Store" ) ;
34+ certRemoveCommand . SetHandler ( RemoveCert ) ;
35+ certRemoveCommand . AddOptions ( new [ ] { _forceOption } . OrderByName ( ) ) ;
36+
2837 this . AddCommands ( new List < Command >
2938 {
30- certEnsureCommand
39+ certEnsureCommand ,
40+ certRemoveCommand ,
3141 } . OrderByName ( ) ) ;
3242 }
3343
@@ -48,4 +58,82 @@ private async Task EnsureCertAsync()
4858
4959 _logger . LogTrace ( "EnsureCertAsync() finished" ) ;
5060 }
61+
62+ public void RemoveCert ( InvocationContext invocationContext )
63+ {
64+ _logger . LogTrace ( "RemoveCert() called" ) ;
65+
66+ try
67+ {
68+ var isForced = invocationContext . ParseResult . GetValueForOption ( _forceOption ) ;
69+ if ( ! isForced )
70+ {
71+ var isConfirmed = PromptConfirmation ( "Do you want to remove the root certificate" , acceptByDefault : false ) ;
72+ if ( ! isConfirmed )
73+ {
74+ return ;
75+ }
76+ }
77+
78+ _logger . LogInformation ( "Uninstalling the root certificate..." ) ;
79+
80+ RemoveTrustedCertificateOnMac ( ) ;
81+ ProxyEngine . ProxyServer . CertificateManager . RemoveTrustedRootCertificate ( machineTrusted : false ) ;
82+
83+ _logger . LogInformation ( "DONE" ) ;
84+ }
85+ catch ( Exception ex )
86+ {
87+ _logger . LogError ( ex , "Error removing certificate" ) ;
88+ }
89+ finally
90+ {
91+ _logger . LogTrace ( "RemoveCert() finished" ) ;
92+ }
93+ }
94+
95+ private static bool PromptConfirmation ( string message , bool acceptByDefault )
96+ {
97+ while ( true )
98+ {
99+ Console . Write ( message + $ " ({ ( acceptByDefault ? "Y/n" : "y/N" ) } ): ") ;
100+ var answer = Console . ReadLine ( ) ;
101+
102+ if ( string . IsNullOrWhiteSpace ( answer ) )
103+ {
104+ return acceptByDefault ;
105+ }
106+ else if ( string . Equals ( "y" , answer , StringComparison . OrdinalIgnoreCase ) )
107+ {
108+ return true ;
109+ }
110+ else if ( string . Equals ( "n" , answer , StringComparison . OrdinalIgnoreCase ) )
111+ {
112+ return false ;
113+ }
114+ }
115+ }
116+
117+ private static void RemoveTrustedCertificateOnMac ( )
118+ {
119+ if ( ! RunTime . IsMac )
120+ {
121+ return ;
122+ }
123+
124+ var bashScriptPath = Path . Join ( ProxyUtils . AppFolder , "remove-cert.sh" ) ;
125+ var startInfo = new ProcessStartInfo ( )
126+ {
127+ FileName = "/bin/bash" ,
128+ Arguments = bashScriptPath ,
129+ UseShellExecute = false ,
130+ CreateNoWindow = true ,
131+ } ;
132+
133+ using var process = new Process ( ) { StartInfo = startInfo } ;
134+ _ = process . Start ( ) ;
135+ process . WaitForExit ( ) ;
136+
137+ HasRunFlag . Remove ( ) ;
138+ }
51139}
0 commit comments