diff --git a/client/acct_mgr.h b/client/acct_mgr.h index ebbd921d693..7ac771601e3 100644 --- a/client/acct_mgr.h +++ b/client/acct_mgr.h @@ -52,6 +52,8 @@ struct ACCT_MGR_INFO : PROJ_AM { // in AM RPCs (used for "farm management") bool no_project_notices; // if set, don't show notices from projects + + // TODO: get rid of the following bool cookie_required; // use of cookies are required during initial signup // NOTE: This bool gets dropped after the client has @@ -60,6 +62,7 @@ struct ACCT_MGR_INFO : PROJ_AM { // if the cookies could not be detected, provide a // link to a website to go to so the user can find // what login name and password they have been assigned + bool password_error; bool send_rec; // send REC in AM RPCs diff --git a/client/acct_setup.cpp b/client/acct_setup.cpp index b730cdf6b0d..9ce7ff483eb 100644 --- a/client/acct_setup.cpp +++ b/client/acct_setup.cpp @@ -220,6 +220,7 @@ int GET_PROJECT_LIST_OP::do_rpc() { void GET_PROJECT_LIST_OP::handle_reply(int http_op_retval) { bool error = false; + error_num = 0; if (http_op_retval) { error_num = http_op_retval; error = true; @@ -232,6 +233,7 @@ void GET_PROJECT_LIST_OP::handle_reply(int http_op_retval) { ); gstate.all_projects_list_check_time = gstate.now; } else { + error_num = ERR_XML_PARSE; error = true; } } @@ -241,10 +243,17 @@ void GET_PROJECT_LIST_OP::handle_reply(int http_op_retval) { gstate.all_projects_list_check_time = gstate.now - ALL_PROJECTS_LIST_CHECK_PERIOD + SECONDS_PER_DAY; } + + // were we initiated by autologin? + // + if (gstate.autologin_fetching_project_list) { + gstate.process_autologin(false); + } } void CLIENT_STATE::all_projects_list_check() { if (cc_config.dont_contact_ref_site) return; + if (get_project_list_op.gui_http->gui_http_state == GUI_HTTP_STATE_BUSY) return; if (all_projects_list_check_time) { if (now - all_projects_list_check_time < ALL_PROJECTS_LIST_CHECK_PERIOD) { return; @@ -253,36 +262,55 @@ void CLIENT_STATE::all_projects_list_check() { get_project_list_op.do_rpc(); } -// called at startup. +// called at startup (first=true) +// or on completion of get project list RPC (first=false). // check for installer filename file. // If present, parse project ID and login token, // and initiate RPC to look up token. // -void CLIENT_STATE::process_autologin() { - int project_id, user_id, n, retval; - char buf[256], login_token[256], *p; +void CLIENT_STATE::process_autologin(bool first) { + static int project_id, user_id; + static char login_token[256]; - // read and parse installer filename - // - FILE* f = boinc_fopen(ACCOUNT_DATA_FILENAME, "r"); - if (!f) return; - fgets(buf, 256, f); - fclose(f); - p = strstr(buf, "__"); - if (!p) { - boinc_delete_file(ACCOUNT_DATA_FILENAME); - return; - } - msg_printf(NULL, MSG_INFO, "Read installer filename file"); - p += 2; - n = sscanf(p, "%d_%d_%[^. ]", &project_id, &user_id, login_token); - // don't include the ".exe" or the " (1)" - if (n != 3) { - msg_printf(NULL, MSG_INFO, "bad account data: %s", buf); - boinc_delete_file(ACCOUNT_DATA_FILENAME); - return; + int n, retval; + char buf[256], *p; + + if (first) { + // read and parse autologin file + // + FILE* f = boinc_fopen(ACCOUNT_DATA_FILENAME, "r"); + if (!f) return; + fgets(buf, 256, f); + fclose(f); + p = strstr(buf, "__"); + if (!p) { + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } + msg_printf(NULL, MSG_INFO, "Read account data file"); + p += 2; + n = sscanf(p, "%d_%d_%[^. ]", &project_id, &user_id, login_token); + // don't include the ".exe" or the " (1)" + if (n != 3) { + msg_printf(NULL, MSG_INFO, "bad account data: %s", buf); + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } + strip_whitespace(login_token); + } else { + // here the get project list RPC finished. + // check whether it failed. + // + autologin_in_progress = false; + if (get_project_list_op.error_num) { + msg_printf(NULL, MSG_INFO, + "get project list RPC failed: %s", + boincerror(get_project_list_op.error_num) + ); + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } } - strip_whitespace(login_token); // check that project ID is valid, get URL // @@ -296,9 +324,29 @@ void CLIENT_STATE::process_autologin() { } PROJECT_LIST_ITEM *pli = project_list.lookup(project_id); if (!pli) { - msg_printf(NULL, MSG_INFO, "Unknown project ID: %d", project_id); - boinc_delete_file(ACCOUNT_DATA_FILENAME); - return; + if (first) { + // we may have an outdated project list. + // Initiate RPC to get newest version + // + retval = get_project_list_op.do_rpc(); + if (retval) { + msg_printf(NULL, MSG_INFO, + "Get project list RPC failed: %s", + boincerror(retval) + ); + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } + autologin_in_progress = true; + // defer GUI RPCs + autologin_fetching_project_list = true; + // tell RPC handler to call us when done + return; + } else { + msg_printf(NULL, MSG_INFO, "Unknown project ID: %d", project_id); + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } } if (!pli->is_account_manager) { @@ -320,14 +368,14 @@ void CLIENT_STATE::process_autologin() { retval = lookup_login_token_op.do_rpc(pli, user_id, login_token); if (retval) { msg_printf(NULL, MSG_INFO, - "lookup token RPC failed: %s", boincerror(retval) + "token lookup RPC failed: %s", boincerror(retval) ); boinc_delete_file(ACCOUNT_DATA_FILENAME); } // disable GUI RPCs until we get an RPC reply // - gstate.enable_gui_rpcs = false; + gstate.autologin_in_progress = true; } int LOOKUP_LOGIN_TOKEN_OP::do_rpc( @@ -345,16 +393,19 @@ int LOOKUP_LOGIN_TOKEN_OP::do_rpc( // If everything checks out, attach to account manager or project. // void LOOKUP_LOGIN_TOKEN_OP::handle_reply(int http_op_retval) { - string user_name, team_name, weak_auth; + string user_name; + string team_name, weak_auth; // returned by projects + string login_name, passwd_hash; // returned by AMs - gstate.enable_gui_rpcs = true; + gstate.autologin_in_progress = false; if (http_op_retval) { + msg_printf(NULL, MSG_INFO, "token lookup RPC failed: %s", boincerror(http_op_retval)); return; } FILE* f = boinc_fopen(LOGIN_TOKEN_LOOKUP_REPLY, "r"); if (!f) { - msg_printf(NULL, MSG_INFO, "lookup token: no reply file"); + msg_printf(NULL, MSG_INFO, "token lookup RPC: no reply file"); boinc_delete_file(ACCOUNT_DATA_FILENAME); return; } @@ -368,21 +419,33 @@ void LOOKUP_LOGIN_TOKEN_OP::handle_reply(int http_op_retval) { continue; } else if (xp.parse_string("weak_auth", weak_auth)) { continue; + } else if (xp.parse_string("login_name", login_name)) { + continue; + } else if (xp.parse_string("passwd_hash", passwd_hash)) { + continue; } } fclose(f); - if (!user_name.size() || !weak_auth.size()) { - msg_printf(NULL, MSG_INFO, "lookup token: missing info"); - boinc_delete_file(ACCOUNT_DATA_FILENAME); - return; - } if (pli->is_account_manager) { + if (!login_name.size() || !passwd_hash.size()) { + msg_printf(NULL, MSG_INFO, "token lookup RPC: missing info"); + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } + msg_printf(NULL, MSG_INFO, "Using account manager %s", pli->name.c_str()); strcpy(gstate.acct_mgr_info.master_url, pli->master_url.c_str()); + strcpy(gstate.acct_mgr_info.login_name, login_name.c_str()); strcpy(gstate.acct_mgr_info.user_name, user_name.c_str()); - strcpy(gstate.acct_mgr_info.password_hash, weak_auth.c_str()); + strcpy(gstate.acct_mgr_info.password_hash, passwd_hash.c_str()); } else { + if (!user_name.size() || !weak_auth.size()) { + msg_printf(NULL, MSG_INFO, "token lookup RPC: missing info"); + boinc_delete_file(ACCOUNT_DATA_FILENAME); + return; + } + msg_printf(NULL, MSG_INFO, "Attaching to project %s", pli->name.c_str()); gstate.add_project( pli->master_url.c_str(), weak_auth.c_str(), pli->name.c_str(), false ); diff --git a/client/client_state.cpp b/client/client_state.cpp index cc90bb362f1..f71e39687c9 100644 --- a/client/client_state.cpp +++ b/client/client_state.cpp @@ -175,7 +175,8 @@ CLIENT_STATE::CLIENT_STATE() must_check_work_fetch = true; retry_shmem_time = 0; no_gui_rpc = false; - enable_gui_rpcs = true; + autologin_in_progress = false; + autologin_fetching_project_list = false; gui_rpc_unix_domain = false; new_version_check_time = 0; all_projects_list_check_time = 0; @@ -731,7 +732,7 @@ int CLIENT_STATE::init() { // check for initialization files // - process_autologin(); + process_autologin(true); acct_mgr_info.init(); project_init.init(); @@ -787,13 +788,12 @@ int CLIENT_STATE::init() { // proxy_info_startup(); - if (gstate.projects.size() == 0) { - msg_printf(NULL, MSG_INFO, - "This computer is not attached to any projects" - ); - msg_printf(NULL, MSG_INFO, - "Visit https://boinc.berkeley.edu for instructions" - ); + if (!autologin_in_progress) { + if (gstate.projects.size() == 0) { + msg_printf(NULL, MSG_INFO, + "This computer is not attached to any projects" + ); + } } // get list of BOINC projects occasionally, @@ -843,7 +843,7 @@ void CLIENT_STATE::do_io_or_sleep(double max_time) { gui_rpc_fds.zero(); http_ops->get_fdset(curl_fds); all_fds = curl_fds; - if (enable_gui_rpcs) { + if (!autologin_in_progress) { gui_rpcs.get_fdset(gui_rpc_fds, all_fds); } diff --git a/client/client_state.h b/client/client_state.h index a769694f553..6fcfcb50eb5 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -92,7 +92,6 @@ struct CLIENT_STATE { FILE_XFER_SET* file_xfers; #ifndef SIM GUI_RPC_CONN_SET gui_rpcs; - bool enable_gui_rpcs; #endif GUI_HTTP gui_http; #ifdef ENABLE_AUTO_UPDATE @@ -247,8 +246,10 @@ struct CLIENT_STATE { double all_projects_list_check_time; // the time we last successfully fetched the project list string newer_version; + bool autologin_in_progress; + bool autologin_fetching_project_list; PROJECT_LIST project_list; - void process_autologin(); + void process_autologin(bool first); // --------------- client_state.cpp: CLIENT_STATE(); diff --git a/client/project_list.cpp b/client/project_list.cpp index 33c2eeee390..7e798957978 100644 --- a/client/project_list.cpp +++ b/client/project_list.cpp @@ -46,6 +46,7 @@ int PROJECT_LIST_ITEM::parse(XML_PARSER& xp, bool is_am) { } int PROJECT_LIST::read_file() { + items.clear(); FILE* f = fopen(ALL_PROJECTS_LIST_FILENAME, "r"); if (!f) return ERR_FOPEN; MIOFILE mf; @@ -56,6 +57,7 @@ int PROJECT_LIST::read_file() { msg_printf(NULL, MSG_INTERNAL_ERROR, "missing start tag in project list file" ); + fclose(f); return ERR_XML_PARSE; } while (!xp.get_tag()) { diff --git a/clientgui/AdvancedFrame.cpp b/clientgui/AdvancedFrame.cpp index 1e2035b8de6..74d71aac045 100644 --- a/clientgui/AdvancedFrame.cpp +++ b/clientgui/AdvancedFrame.cpp @@ -1884,7 +1884,7 @@ void CAdvancedFrame::OnConnect(CFrameEvent& WXUNUSED(event)) { // m_pNotebook->SetSelection(ID_ADVNOTICESVIEW - ID_ADVVIEWBASE); } - } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach && !autoattach_in_progress()) { + } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach) { // client isn't attached to any projects. // Look for an account to attach to, either in project_init.xml // or in browser cookies diff --git a/clientgui/AsyncRPC.cpp b/clientgui/AsyncRPC.cpp index 47de6a9430a..ee946e79d6f 100644 --- a/clientgui/AsyncRPC.cpp +++ b/clientgui/AsyncRPC.cpp @@ -36,7 +36,9 @@ extern bool s_bSkipExitConfirmation; -// Delay in milliseconds before showing AsyncRPCDlg +// Delay in milliseconds before showing AsyncRPCDlg during auto-attach to project +#define RPC_WAIT_DLG_DELAY_DURING_AUTOATTACH 60000 +// Delay in milliseconds before showing AsyncRPCDlg normally #define RPC_WAIT_DLG_DELAY 1500 // How often to check for events when minimized and waiting for Demand RPC #define DELAY_WHEN_MINIMIZED 500 @@ -474,7 +476,7 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { int retval = 0; int response = wxID_OK; wxMutexError mutexErr = wxMUTEX_NO_ERROR; - long delayTimeRemaining, timeToSleep; + long timeToDelay, delayTimeRemaining, timeToSleep; bool shown = false; if (!m_RPCThread) return -1; @@ -544,18 +546,29 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { return -1; } // Don't show dialog if RPC completes before RPC_WAIT_DLG_DELAY - // or while BOINC is minimized + // or while BOINC is minimized or during auto-attach to project CBOINCBaseFrame* pFrame = wxGetApp().GetFrame(); wxStopWatch Dlgdelay = wxStopWatch(); m_RPCWaitDlg = new AsyncRPCDlg(); m_bWaitingForRPC = true; + if (m_bAutoAttaching) { + // client may auto-attach only when first launched + // so don't keep checking once it is false + m_bAutoAttaching = autoattach_in_progress(); + } // Allow RPC_WAIT_DLG_DELAY seconds for Demand RPC to complete before // displaying "Please Wait" dialog, but keep checking for completion. - delayTimeRemaining = RPC_WAIT_DLG_DELAY; + if (m_bAutoAttaching) { + timeToDelay = RPC_WAIT_DLG_DELAY_DURING_AUTOATTACH; + } else { + timeToDelay = RPC_WAIT_DLG_DELAY; + } + + delayTimeRemaining = timeToDelay; while (true) { if (delayTimeRemaining >= 0) { // Prevent overflow if minimized for a very long time - delayTimeRemaining = RPC_WAIT_DLG_DELAY - Dlgdelay.Time(); + delayTimeRemaining = timeToDelay - Dlgdelay.Time(); } if (pFrame) { @@ -583,7 +596,7 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { wxSafeYield(NULL, true); } - // OnRPCComplete() clears m_bWaitingForRPC if RPC completed + // OnRPCComplete() clears m_bWaitingForRPC and deletes m_RPCWaitDlg if RPC completed if (! m_bWaitingForRPC) { return retval; } @@ -748,8 +761,8 @@ void CMainDocument::HandleCompletedRPC() { if (m_RPCWaitDlg->IsShown()) { m_RPCWaitDlg->EndModal(wxID_OK); } - m_RPCWaitDlg->Destroy(); - m_RPCWaitDlg = NULL; + m_RPCWaitDlg->Destroy(); + m_RPCWaitDlg = NULL; } m_bWaitingForRPC = false; } diff --git a/clientgui/MainDocument.cpp b/clientgui/MainDocument.cpp index 765b67d22aa..12abdfed934 100644 --- a/clientgui/MainDocument.cpp +++ b/clientgui/MainDocument.cpp @@ -477,6 +477,9 @@ int CMainDocument::OnInit() { m_pClientManager = new CBOINCClientManager(); wxASSERT(m_pClientManager); + // client may auto-attach only when first launched + m_bAutoAttaching = autoattach_in_progress(); + m_RPCWaitDlg = NULL; m_bWaitingForRPC = false; m_bNeedRefresh = false; diff --git a/clientgui/MainDocument.h b/clientgui/MainDocument.h index f64cc9ca051..17151c375ab 100644 --- a/clientgui/MainDocument.h +++ b/clientgui/MainDocument.h @@ -214,6 +214,7 @@ class CMainDocument : public wxObject { BOINC_Condition* m_pRPC_Request_Condition; wxDateTime m_dtLasAsyncRPCDlgTime; wxDateTime m_dtLastFrameViewRefreshRPCTime; + bool m_bAutoAttaching; // // Projects Tab diff --git a/clientgui/sg_BoincSimpleFrame.cpp b/clientgui/sg_BoincSimpleFrame.cpp index 0dd01f2220f..58f7319f36f 100644 --- a/clientgui/sg_BoincSimpleFrame.cpp +++ b/clientgui/sg_BoincSimpleFrame.cpp @@ -832,7 +832,7 @@ void CSimpleFrame::OnConnect(CFrameEvent& WXUNUSED(event)) { } #endif } - } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach && !autoattach_in_progress()) { + } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach) { if (pis.url.size() > 0) { strProjectName = pis.name.c_str(); diff --git a/html/user/login_token_lookup.php b/html/user/login_token_lookup.php index ad2b1d978d6..b0c828b2fec 100644 --- a/html/user/login_token_lookup.php +++ b/html/user/login_token_lookup.php @@ -23,6 +23,7 @@ require_once("../inc/xml.inc"); function main() { + global $config; $user_id = get_str("user_id"); $token = get_str("token"); $user = BoincUser::lookup_id($user_id); @@ -35,18 +36,22 @@ function main() { if (time() - $user->login_token_time > 86400) { xml_error("token timed out"); } - $name = htmlentities($user->name); - $auth = weak_auth($user); - echo " - $auth - $name -"; - if ($user->teamid && $team == BoincTeam::lookup_id($user->teamid)) { - $name = htmlentities($team->name); - echo " $name\n"; + $uname = htmlentities($user->name); + echo "\n"; + if (parse_bool($config, "account_manager")) { + echo " $uname\n"; + echo " $user->email_addr\n"; + echo " $user->passwd_hash\n"; + } else { + $auth = weak_auth($user); + echo " $auth\n"; + echo " $uname\n"; + if ($user->teamid && $team == BoincTeam::lookup_id($user->teamid)) { + $tname = htmlentities($team->name); + echo " $tname\n"; + } } - echo " -"; + echo "\n"; } main(); diff --git a/lib/common_defs.h b/lib/common_defs.h index 4468d2e3fcd..68b224ec439 100644 --- a/lib/common_defs.h +++ b/lib/common_defs.h @@ -354,7 +354,8 @@ struct DEVICE_STATUS { #define GRAPHICS_APP_FILENAME "graphics_app" #define GUI_RPC_PASSWD_FILE "gui_rpc_auth.cfg" #define SS_CONFIG_FILE "ss_config.xml" -#define ACCOUNT_DATA_FILENAME "account_data.txt" +#define ACCOUNT_DATA_FILENAME "login_token.txt" + // can't call this account*; it would be mistaken for an account file #ifdef _WIN32 #define DEFAULT_SS_EXECUTABLE "boincscr.exe" diff --git a/mac_installer/Installer.cpp b/mac_installer/Installer.cpp index b7f7724af2d..939748ac6de 100644 --- a/mac_installer/Installer.cpp +++ b/mac_installer/Installer.cpp @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) if (p) *p = '\0'; - p = strstr(brand, " Installer.app"); // Strip off trailing " Installer.app" + p = strrchr(brand, ' '); // Strip off last space character and everything following if (p) *p = '\0'; diff --git a/win_build/installerv2/BOINCx64.ism b/win_build/installerv2/BOINCx64.ism index af084a01113..7a286647bf5 100644 --- a/win_build/installerv2/BOINCx64.ism +++ b/win_build/installerv2/BOINCx64.ism @@ -1798,7 +1798,7 @@ ISBuildSourcePath ISAttributes ISComponentSubFolder_ - all_projects_list.xml_BOINCDataALL_PR~1.XML|all_projects_list.xml065535.0.0.001<ISProjectFolder>\redist\all_projects_list.xml17 + all_projects_list.xml_BOINCDataALL_PR~1.XML|all_projects_list.xml001<ISProjectFolder>\redist\all_projects_list.xml1 boinc.exe_BOINCboinc.exe01<PATH_TO_RELEASE_FILES>\boinc.exe1 boinc.exe1BOINCServiceConfigboinc.exe01<PATH_TO_RELEASE_FILES>\boinc.exe1 boinc.scr_Screensaverboinc.scr01<PATH_TO_RELEASE_FILES>\boinc.scr1 @@ -4551,7 +4551,7 @@ VwBlAGIAAQBXAEUAQgB4ADYANAA= PROGMSG_IIS_ROLLBACKAPPPOOLS##IDS_PROGMSG_IIS_ROLLBACKAPPPOOLS## PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## PROGRAMFILETOLAUNCHATEND[#boincmgr.exe] - ProductCode{BAB089D7-D07A-44D4-83B3-2DA936BA2333} + ProductCode{A94AB3A9-7A06-4D32-9CCD-04F37C8EB11D} ProductIDnone ProductLanguage1033 ProductNameBOINC diff --git a/win_build/installerv2/redist/all_projects_list.xml b/win_build/installerv2/redist/all_projects_list.xml index b4d3ba4ff2e..38863decbbf 100644 --- a/win_build/installerv2/redist/all_projects_list.xml +++ b/win_build/installerv2/redist/all_projects_list.xml @@ -1036,7 +1036,7 @@ Onboard 101 - https://onboard.berkeley.edu/ + https://boinc.berkeley.edu/test2/ Onboard prototype https://boinc.berkeley.edu/images/