GME  13
Prompter.cpp
Go to the documentation of this file.
00001 
00023 #include "../StdAfx.h"
00024 
00025 #if(USESVN)
00026 
00027 #include "Prompter.h"
00028 #include "Pool.h"
00029 #include "svn_client.h"
00030 #include "conio.h"
00031 #include "Util.h"
00032 #include "..\\CredentialDlg.h"
00033 #include "..\\CertificateDlg.h"
00034 #include <iostream> // remove this later
00035 
00036 extern std::string g_userName;
00037 extern std::string g_passWord;
00038 
00039 //static
00040 void PromptImpl::scanfBlind( std::string& ret)
00041 {
00042         ASSERT(0);
00043         int k = 0;
00044         ret.clear();
00045 
00046         // blind scanf like:
00047         while( 13 != ( k = getch()) && 10 != k)
00048         {
00049                 if( k != 8)
00050                 {
00051                         std::cout << "*";
00052                         ret += (char) k;
00053                 }
00054                 else
00055                 {
00056                         ret = ret.substr( 0, ret.length() - 1); // remove last one
00057                         std::cout << "Backspace, please continue typing " << std::endl << std::string( ret.length(), '*');
00058                 }
00059         }
00060         if( k == 13 || k == 10)
00061                 std::cout << std::endl;
00062 }
00063 
00064 GPromptImpl::GPromptImpl()
00065 : m_pWord( "-")
00066 , m_uName( "-")
00067 , m_credsFilled( false)
00068 {
00069 }
00070 
00071 GPromptImpl::~GPromptImpl()
00072 {
00073 }
00074 
00075 std::string GPromptImpl::username()
00076 {
00077         // assumes that prompt() was called before, 
00078         // and the m_uName field was filled already 
00079         if( m_credsFilled && m_uName.size() > 0 && m_uName != "-")  // the default value
00080                 return m_uName;
00081 
00082         ASSERT(0);
00083         CCredentialDlg dlg( true, false, false, m_uName, (const char*) 0);
00084         if( dlg.DoModal() == IDOK)
00085         {
00086                 m_uName = dlg.name();
00087                 //m_pWord = dlg.word();
00088                 //m_credsFilled = true;
00089         }
00090 
00091         return m_uName;
00092 }
00093 
00094 std::string GPromptImpl::password()
00095 {
00096         if( m_credsFilled && m_pWord.size() > 0 && m_pWord != "-")// && m_maySave) // if not the default value ("-") and only if allowed to be saved
00097                 return m_pWord;
00098 
00099         ASSERT(0);
00100         CCredentialDlg dlg( false, false, false, m_uName, (const char*) 0);
00101         if( dlg.DoModal() == IDOK)
00102         {
00103                 m_uName = dlg.name();
00104                 m_pWord = dlg.word();
00105                 m_credsFilled = true;
00106         }
00107         return m_pWord;
00108 }
00109 
00110 bool GPromptImpl::askYesNo(const char *realm, const char *question, 
00111                         bool yesIsDefault)
00112 {
00113         std::string msg = "Realm: " + std::string( realm ? realm:"<norealm>") + "\nQuestion: " + std::string( question ? question :"<noquestion>");
00114         int res = AfxMessageBox( msg.c_str(), MB_YESNO);
00115         if( IDYES == res)
00116                 return true;
00117         else if( IDNO == res)
00118                 return false;
00119         else
00120                 return yesIsDefault;
00121 }
00122 
00123 std::string GPromptImpl::askQuestion(const char *realm, const char *question, 
00124                                   bool showAnswer, bool maySave)
00125 {
00126         std::string msg = "Realm: " + std::string( realm ? realm:"<norealm>") + "\nQuestion: " + std::string( question ? question :"<noquestion>");
00127         if( IDYES == AfxMessageBox( msg.c_str(), MB_YESNO))
00128                 m_answer = "y";
00129         else
00130                 m_answer = "n";
00131 
00132         m_maySave = false;
00133         msg = "May save the answer?";
00134         if( IDYES == AfxMessageBox( msg.c_str(), MB_YESNO))
00135                 m_maySave = true;
00136 
00137         return m_answer;
00138 }
00139 
00140 int GPromptImpl::askTrust(const char *question, bool maySave)
00141 {
00142         std::string q = question; 
00143         int offs = 0; // make it Windows multiline: \r\n instead of \n
00144         while( (offs = q.find( '\n', offs + 1)) != -1)
00145         {
00146                 q.insert( offs, "\r"); offs += 2;
00147         }
00148         //if(maySave)
00149         //{
00150         //      q += "(R)eject, accept (t)emporarily or accept (p)ermanently?";
00151         //}
00152         //else
00153         //{
00154         //      q += "(R)eject or accept (t)emporarily?";
00155         //}
00156 
00157         CCertificateDlg dlg( q, maySave, 0);
00158         if( dlg.DoModal() == IDOK)
00159         {
00160                 CCertificateDlg::Response rp = dlg.getResp();
00161                 if( rp == CCertificateDlg::PermanentAccept)
00162                         return Prompter::AcceptPermanently;
00163                 else if( rp == CCertificateDlg::TemoraryAccept)
00164                         return Prompter::AcceptTemporary;
00165                 else
00166                         return Prompter::Reject;
00167         }
00168         return Prompter::Reject;
00169 }
00170 
00171 bool GPromptImpl::prompt(const char *p_realm, const char *p_username, bool p_maySave)
00172 {
00173         std::string u_name( p_username?p_username: "<<nousername>>");
00174         //std::string msg = "Realm: \t'" + std::string( p_realm?p_realm:"<<norealm>>") + "'\nUser: \t'" + u_name + "'\nChange user credentials?";
00175         //if( IDYES == AfxMessageBox( msg.c_str(), MB_YESNO))
00176         if( 1)
00177         {
00178                 CCredentialDlg dlg( false, true, p_maySave, u_name, p_realm);
00179                 if( dlg.DoModal() == IDOK)
00180                 {
00181                         m_uName = dlg.name();
00182                         m_pWord = dlg.word();
00183                         m_credsFilled = true;
00184                         if( p_maySave)
00185                         {
00186                                 m_maySave = dlg.maySave();
00187                                 if( m_maySave)
00188                                 {
00189                                         g_userName = m_uName;
00190                                         g_passWord = m_pWord;
00191                                         // todo: then save it by using the special set_password
00192                                         //
00193                                 }
00194                         }
00195                         else
00196                                 m_maySave = false;
00197                 }
00198         }
00199         else // User selected not to change user credentials
00200         {
00201                 m_uName = p_username;
00202                 //m_pWord = "-";
00203         }
00204 
00205         return true;
00206 }
00207 
00208 
00209 //#include "svn_private_config.h"
00210 TextPromptImpl::TextPromptImpl()
00211 : m_pWord( "-")
00212 , m_uName( "-")
00213 {
00214 }
00215 
00216 std::string TextPromptImpl::readcnf( const EntryType& p_type)
00217 {
00218         if( p_type == UserName)
00219         {
00220                 return "username";
00221         }
00222         else if( p_type == Password)
00223         {
00224                 return m_pWord.size() > 0 ? m_pWord : "<<no pw?>>";
00225         }
00226         return "";
00227 }
00228 
00229 TextPromptImpl::~TextPromptImpl()
00230 {
00231 }
00232 
00233 std::string TextPromptImpl::username()
00234 {
00235         // assumes that prompt() was called before, 
00236         // and the m_uName field was filled already 
00237 
00238         if( m_uName.size() > 0 && m_uName != "-")  // the default value
00239                 return m_uName;
00240 
00241         return readcnf( UserName);
00242 }
00243 
00244 std::string TextPromptImpl::password()
00245 {
00246         if( m_pWord.size() > 0 && m_pWord != "-" && m_maySave) // if not the default value ("-") and only if allowed to be saved
00247                 return m_pWord;
00248 
00249         // require it
00250         std::cout << "Password please : ";
00251         std::string ret;
00252         scanfBlind( ret);
00253         //if( 1 == scanf( "%s", &buff)) // cin eliminates whitespaces
00254                 //ret = buff;
00255         //ret = readcnf( EntryType::Password);
00256 
00257         if( m_maySave)
00258         {
00259                 m_pWord = ret;
00260         }
00261         return ret;
00262 }
00263 
00264 bool TextPromptImpl::askYesNo(const char *realm, const char *question, 
00265                         bool yesIsDefault)
00266 {
00267         std::cout << "\nRealm: " << (realm?realm:"<<norealm>>") << "\nQuestion: " << question;
00268         
00269         //int k = getch();
00270         std::string res;
00271         std::cin >> res;
00272         int k = res.size() > 0 ? res[0]: ' ';
00273         if( (char) k == 'n' || (char) k == 'N')
00274                 return false;
00275         else if( (char) k == 'y' || (char) k == 'Y')
00276                 return true;
00277         else // if yesIsDefault return true = Yes, if !yesisDefault return false = No
00278                 return yesIsDefault;
00279 }
00280 
00281 std::string TextPromptImpl::askQuestion(const char *realm, const char *question, 
00282                                   bool showAnswer, bool maySave)
00283 {
00284         std::cout << "\nRealm: " << (realm?realm:"<norealm>") << "\nQuestion: " << (question?question:"<noquestion>");
00285         std::string ret;
00286         std::cin >> ret;
00287         m_answer = ret;
00288     if(maySave)
00289         m_maySave = askYesNo(realm, "May save the answer ?", true);
00290     else
00291         m_maySave = false;
00292 
00293         return m_answer;
00294 }
00295 
00296 int TextPromptImpl::askTrust(const char *question, bool maySave)
00297 {
00298         std::string q = question;
00299         if(maySave)
00300         {
00301                 q += "(R)eject, accept (t)emporarily or accept (p)ermanently?";
00302         }
00303         else
00304         {
00305                 q += "(R)eject or accept (t)emporarily?";
00306         }
00307         std::string s_answer = askQuestion( NULL, q.c_str(), true, false);
00308         char answer = (s_answer.size() > 0)? s_answer[0]: ' ';
00309         if( answer == 't' || answer == 'T')
00310         {
00311                 return Prompter::AcceptTemporary;
00312         }
00313         else if(maySave && (answer == 'p' || answer == 'P'))
00314         {
00315                 return Prompter::AcceptPermanently;
00316         }
00317         else
00318                 return Prompter::Reject;
00319 }
00320 
00321 bool TextPromptImpl::prompt(const char *p_realm, const char *p_username, bool p_maySave)
00322 {
00323         // aren't we too ambitious here
00324         std::cout << "\nRealm: " << (p_realm?p_realm:"<<norealm>>") << std::endl << "-Username-: '" << (p_username?p_username: "<<zerousernameptr>>") << "'";
00325         if( askYesNo( p_realm, "Change user name?", false))
00326         {
00327                 std::cout << "Username please : ";
00328                 std::cin >> m_uName; // what about storing retv somewhere?
00329 
00330                 std::cout << "Password for '" << m_uName << "' please : ";
00331                 scanfBlind( m_pWord);
00332 
00333                 if( p_maySave)
00334                 {
00335                         m_maySave = askYesNo( p_realm, "May save the answer ?", true);
00336                         if( m_maySave)
00337                         {
00338                                 g_userName = m_uName;
00339                                 g_passWord = m_pWord;
00340                                 // todo: then save it by using the special set_password
00341                                 //
00342                         }
00343                 }
00344                 else
00345                         m_maySave = false;
00346 
00347                 return true;
00348         }
00349         else
00350                 m_uName = p_username;
00351 
00352         return true;
00353 }
00354 
00355 //**************************************
00356 //*************************************
00357 
00358 Prompter::Prompter( PromptImpl* p_prompter)
00359 {
00360     m_impl = p_prompter;
00361 }
00362 
00363 Prompter::~Prompter()
00364 {
00365     if( m_impl)
00366         {
00367                 delete m_impl;
00368         }
00369 }
00370 
00371 Prompter* Prompter::makePrompter( PromptImpl* p_promptImpl)
00372 {
00373     return new Prompter( p_promptImpl);
00374 }
00375 
00376 svn_auth_provider_object_t*   Prompter::getProviderSimple(apr_pool_t *pool)
00377 {
00378     svn_auth_provider_object_t *provider;
00379     svn_client_get_simple_prompt_provider (&provider,
00380                                            CallbackHelpers::simple_prompt, /* prompt function */
00381                                            m_impl,                         /* prompt baton    */
00382                                            2, /* retry limit */
00383                                            pool);
00384 
00385     return provider;
00386 }
00387 
00388 svn_auth_provider_object_t*   Prompter::getProviderUsername(apr_pool_t *pool)
00389 {
00390     svn_auth_provider_object_t *provider;
00391     svn_client_get_username_prompt_provider (&provider,
00392                                              CallbackHelpers::username_prompt, /* prompt function */
00393                                              m_impl,                           /* prompt baton    */
00394                                              2, /* retry limit */
00395                                              pool);
00396 
00397     return provider;
00398 }
00399 
00400 svn_auth_provider_object_t*   Prompter::getProviderServerSSLTrust(apr_pool_t *pool)
00401 {
00402     svn_auth_provider_object_t *provider;
00403     svn_client_get_ssl_server_trust_prompt_provider
00404                 (&provider, CallbackHelpers::ssl_server_trust_prompt, m_impl, pool);
00405 
00406     return provider;
00407 }
00408 
00409 svn_auth_provider_object_t*   Prompter::getProviderClientSSL(apr_pool_t *pool)
00410 {
00411     svn_auth_provider_object_t *provider;
00412     svn_client_get_ssl_client_cert_prompt_provider
00413           (&provider, CallbackHelpers::ssl_client_cert_prompt, m_impl, 2, /* retry limit */pool);
00414 
00415     return provider;
00416 }
00417 
00418 svn_auth_provider_object_t*   Prompter::getProviderClientSSLPassword(apr_pool_t *pool)
00419 {
00420     svn_auth_provider_object_t *provider;
00421     svn_client_get_ssl_client_cert_pw_prompt_provider
00422           (&provider, CallbackHelpers::ssl_client_cert_pw_prompt, m_impl, 2 /* retry limit */,
00423                                                          pool);
00424 
00425     return provider;
00426 }
00427 
00428 // *********************************************************************************************
00429 // *********************** C A L L B A C K   H E L P E R   M E T H O D S ***********************
00430 // *********************************************************************************************
00431 
00432 // static, callback
00433 svn_error_t *Prompter::CallbackHelpers::simple_prompt(svn_auth_cred_simple_t **cred_p, 
00434                                      void *baton,
00435                                      const char *realm, const char *username, 
00436                                      svn_boolean_t may_save,
00437                                      apr_pool_t *pool)
00438 {
00439         // SVN_AUTH_CRED_SIMPLE [svn.simple] credentials ( svn_auth_cred_simple_t ) comprise of
00440         // const char *username;
00441         // const char *password;
00442         // svn_boolean_t may_save;
00443         // This latter indicates if the credentials may be saved (to disk). 
00444         // For example, a GUI prompt implementation with a remember password
00445         // checkbox shall set may_save to TRUE if the checkbox is checked.
00446 
00447         PromptImpl *that = (PromptImpl*)baton;
00448         svn_auth_cred_simple_t *ret = (svn_auth_cred_simple_t*)apr_pcalloc(pool, sizeof(*ret));
00449 
00450         // show dlg
00451         if(!that->prompt( realm, username, may_save ? true : false))
00452                 return svn_error_create( SVN_ERR_RA_NOT_AUTHORIZED, NULL, "User canceled dialog");
00453 
00454         // retrieve uname
00455         std::string user = that->username();
00456         if(user == "")
00457                 return svn_error_create( SVN_ERR_RA_NOT_AUTHORIZED, NULL, "User canceled dialog");
00458 
00459         // duplicate uname into return variable
00460         ret->username = apr_pstrdup( pool, user.c_str());
00461 
00462         // retrieve passwrd
00463         std::string pass = that->password();
00464         if(pass == "")
00465                 return svn_error_create( SVN_ERR_RA_NOT_AUTHORIZED, NULL, "User canceled dialog");
00466 
00467         // duplicate password into return variable
00468         ret->password  = apr_pstrdup( pool, pass.c_str());
00469 
00470         // retrieve may_save option
00471         ret->may_save = that->m_maySave;
00472 
00473         *cred_p = ret;
00474         return SVN_NO_ERROR;
00475 }
00476 
00477 // static, callback
00478 svn_error_t*   Prompter::CallbackHelpers::username_prompt(svn_auth_cred_username_t **cred_p, 
00479                                        void *baton,
00480                                        const char *realm, 
00481                                        svn_boolean_t may_save, 
00482                                        apr_pool_t *pool)
00483 {
00484         // SVN_AUTH_CRED_USERNAME [svn.username] credentials ( svn_auth_cred_username_t ) comprise of
00485         // const char *username;
00486         // svn_boolean_t may_save;
00487         // This latter indicates if the credentials may be saved (to disk). 
00488         // For example, a GUI prompt implementation with a remember username
00489         // checkbox shall set may_save to TRUE if the checkbox is checked.
00490 
00491         PromptImpl *that = (PromptImpl*)baton;
00492         svn_auth_cred_username_t *ret = (svn_auth_cred_username_t*)apr_pcalloc(pool, sizeof(*ret));
00493 
00494         // show question
00495         std::string user = that->askQuestion( realm, "[svn.username] Username: ", true, may_save ? true : false);
00496         if(user == "")
00497                 return svn_error_create( SVN_ERR_RA_NOT_AUTHORIZED, NULL, "User canceled dialog");
00498 
00499         // duplicate uname into return variable
00500         ret->username = apr_pstrdup(pool,user.c_str());
00501 
00502         // retrieve may_save option
00503         ret->may_save = that->m_maySave;
00504 
00505         *cred_p = ret;
00506         return SVN_NO_ERROR;
00507 }
00508 
00509 // static, callback
00510 svn_error_t*   Prompter::CallbackHelpers::ssl_server_trust_prompt(
00511                               svn_auth_cred_ssl_server_trust_t **cred_p,
00512                               void *baton,
00513                               const char *realm,
00514                               apr_uint32_t failures,
00515                               const svn_auth_ssl_server_cert_info_t *cert_info,
00516                               svn_boolean_t may_save,
00517                                apr_pool_t *pool)
00518 {
00519         PromptImpl *that = (PromptImpl*)baton;
00520         svn_auth_cred_ssl_server_trust_t *ret = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc(pool, sizeof(*ret));
00521 
00522         std::string question = "Error validating server certificate for ";
00523         question += realm;
00524         question += ":\n";
00525 
00526         if(failures & SVN_AUTH_SSL_UNKNOWNCA)
00527         {
00528                 question += " - Unknown certificate issuer\n";
00529                 question += "   Fingerprint: ";
00530                 question += cert_info->fingerprint;
00531                 question += "\n";
00532                 question += "   Distinguished name: ";
00533                 question += cert_info->issuer_dname;
00534                 question += "\n";
00535         }
00536 
00537         if(failures & SVN_AUTH_SSL_CNMISMATCH)
00538         {
00539                 question += " - Hostname mismatch (";
00540                 question += cert_info->hostname;
00541                 question += ")\n";
00542         }
00543 
00544         if(failures & SVN_AUTH_SSL_NOTYETVALID)
00545         {
00546                 question += " - Certificate is not yet valid\n";
00547                 question += "   Valid from ";
00548                 question += cert_info->valid_from;
00549                 question += "\n";
00550         }
00551 
00552         if(failures & SVN_AUTH_SSL_EXPIRED)
00553         {
00554                 question += " - Certificate is expired\n";
00555                 question += "   Valid until ";
00556                 question += cert_info->valid_until;
00557                 question += "\n";
00558         }
00559 
00560         switch( that->askTrust( question.c_str(), may_save ? true : false))
00561         {
00562         case AcceptTemporary:
00563                 *cred_p = ret;
00564                 ret->may_save = FALSE;
00565                 break;
00566         case AcceptPermanently:
00567                 *cred_p = ret;
00568                 ret->may_save = TRUE;
00569                 ret->accepted_failures = failures;
00570                 break;
00571         default:
00572                 *cred_p = NULL;
00573         }
00574         return SVN_NO_ERROR;
00575 }
00576 
00577 // static, callback
00578 svn_error_t*   Prompter::CallbackHelpers::ssl_client_cert_prompt(
00579                                      svn_auth_cred_ssl_client_cert_t **cred_p,
00580                                      void *baton, 
00581                                      const char *realm, 
00582                                      svn_boolean_t may_save,
00583                                      apr_pool_t *pool)
00584 {
00585         PromptImpl *that = (PromptImpl*)baton;
00586         svn_auth_cred_ssl_client_cert_t *ret = (svn_auth_cred_ssl_client_cert_t*)apr_pcalloc(pool, sizeof(*ret));
00587 
00588         std::string cert_file = that->askQuestion( realm, "client certificate filename: ", true, may_save ? true : false);
00589         if(cert_file == "")
00590                 return svn_error_create( SVN_ERR_RA_NOT_AUTHORIZED, NULL, "User canceled dialog");
00591 
00592         ret->cert_file = apr_pstrdup(pool, cert_file.c_str());
00593         ret->may_save = that->m_maySave;
00594         *cred_p = ret;
00595 
00596         return SVN_NO_ERROR;
00597 }
00598 
00599 // static, callback
00600 svn_error_t*   Prompter::CallbackHelpers::ssl_client_cert_pw_prompt(
00601                                   svn_auth_cred_ssl_client_cert_pw_t **cred_p,
00602                                   void *baton, 
00603                                   const char *realm, 
00604                                   svn_boolean_t may_save,
00605                                   apr_pool_t *pool)
00606 {
00607         PromptImpl *that = (PromptImpl*)baton;
00608         svn_auth_cred_ssl_client_cert_pw_t *ret = (svn_auth_cred_ssl_client_cert_pw_t*)apr_pcalloc(pool, sizeof(*ret));
00609 
00610         std::string info = that->askQuestion( realm, "client certificate passphrase: ", false, may_save ? true : false);
00611         if(info == "")
00612                 return svn_error_create( SVN_ERR_RA_NOT_AUTHORIZED, NULL, "User canceled dialog");
00613 
00614         ret->password = apr_pstrdup( pool, info.c_str());
00615         ret->may_save = that->m_maySave;
00616         *cred_p = ret;
00617 
00618         return SVN_NO_ERROR;
00619 }
00620 
00621 // *********************************************************************************************
00622 //  E O F
00623 // *********************************************************************************************
00624 
00625 #endif