12b38c2f48370c2841be48879199ab7e9eea4047 chinhli Wed Apr 25 16:33:57 2012 -0700 Finished new Login and Signup UI from Greg. diff --git src/hg/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c index 3426b18..62f68cc 100644 --- src/hg/hgLogin/hgLogin.c +++ src/hg/hgLogin/hgLogin.c @@ -15,62 +15,62 @@ #include "web.h" #include "ra.h" #include "hgColors.h" #include <crypt.h> #include <openssl/md5.h> #include "net.h" #include "hgLogin.h" #include "hgLoginLink.h" #include "gbMembers.h" #include "versionInfo.h" char msg[2048] = ""; -char *excludeVars[] = { "submit", "Submit", "debug", "fixMembers", "update", "hgLogin_password","hgLogin_confirmPW", NULL }; +char *excludeVars[] = { "submit", "Submit", "debug", "fixMembers", "update", "hgLogin_password","hgLogin_password2", NULL }; /* The excludeVars are not saved to the cart. (We also exclude * any variables that start "near.do.") */ /* ---- Global variables. ---- */ struct cart *cart; /* This holds cgi and other variables between clicks. */ char *database; /* Name of genome database - hg15, mm3, or the like. */ struct hash *oldCart; /* Old cart hash. */ char *errMsg; /* Error message to show user when form data rejected */ /* -------- password functions ---- */ void cryptWikiWay(char *password, char *salt, char* result) // encrypt password as mediawiki does: ':B:'.$salt.':'. md5($salt.'-'.md5($password ) { int i; unsigned char result1[MD5_DIGEST_LENGTH]; unsigned char result2[MD5_DIGEST_LENGTH]; char firstMD5[MD5_DIGEST_LENGTH*2 + 1]; char secondMD5[MD5_DIGEST_LENGTH*2 + 1]; i = MD5_DIGEST_LENGTH; // /*DEBUG*/ printf("MD5_DIGEST_LENGT is -- %d\n",i); MD5((unsigned char *) password, strlen(password), result1); // output /****************************************************** DEBUG printf("result1 array:\n"); for(i = 0; i < MD5_DIGEST_LENGTH; i++) printf("%02x", result1[i]); printf("\n"); ************************************************************/ // Convert the first MD5 value to string - printf("Convert result1 to firstMD5 .......\n"); + // /* DEBUG */ printf("Convert result1 to firstMD5 .......\n"); for(i = 0; i < MD5_DIGEST_LENGTH; i++) { sprintf(&firstMD5[i*2], "%02x", result1[i]); } /****************************************************** DEBUG printf("\n"); printf("firstMD5 string\n"); printf("firstMD5 is: %s \n",firstMD5); printf("\n"); ***************************************************************/ // add the salt with "-" char saltDashMD5[256]; strcpy(saltDashMD5,salt); // /*DEBUG*/ printf("String3 is: %s \n",saltDashMD5); strcat(saltDashMD5,"-"); @@ -165,47 +165,30 @@ saltSize = sizeof(salt); findSalt(encPassword, salt, saltSize); char encPwd[45] = ""; // encryptPWD(password, encPassword, encPwd, sizeof(encPwd)); encryptPWD(password, salt, encPwd, sizeof(encPwd)); if (sameString(encPassword,encPwd)) { return TRUE; } else { return FALSE; } } - -boolean checkPwdCharClasses(char *password) -/* check that password uses at least 2 character classes */ -{ -/* [A-Z] [a-z] [0-9] [!@#$%^&*()] */ -int classes[4]={0,0,0,0}; -char c; -while ((c=*password++)) - { - if (c >= 'A' && c <= 'Z') classes[0] = 1; - if (c >= 'a' && c <= 'z') classes[1] = 1; - if (c >= '0' && c <= '9') classes[2] = 1; - if (strchr("!@#$%^&*()",c)) classes[3] = 1; - } -return ((classes[0]+classes[1]+classes[2]+classes[3])>=2); -} - unsigned int randInt(unsigned int n) /* little randome number helper returns 0 to n-1 */ { return (unsigned int) n * (rand() / (RAND_MAX + 1.0)); } char *generateRandomPassword() /* Generate valid random password for users who have lost their old one. * Free the returned value.*/ { char boundary[256]; char punc[] = "!@#$%^&*()"; /* choose a new string for the boundary */ /* Set initial seed */ int i = 0; @@ -465,41 +448,31 @@ if (!checkPwd(currentPassword, password)) { freez(&errMsg); errMsg = cloneString("Invalid current password."); changePasswordPage(conn); return; } freez(&password); if (!newPassword || sameString(newPassword,"") || (strlen(newPassword)<5)) { freez(&errMsg); errMsg = cloneString("New password must be at least 5 characters long."); changePasswordPage(conn); return; } -/*************************** -if (!checkPwdCharClasses(newPassword)) - { - freez(&errMsg); - errMsg = cloneString( - "Password must contain characters from 2 of the following 4 classes: " - "[A-Z] [a-z] [0-9] [!@#$%^&*()]."); - changePasswordPage(conn); - return; - } -********************************************/ + char encPwd[45] = ""; encryptNewPwd(newPassword, encPwd, sizeof(encPwd)); safef(query,sizeof(query), "update gbMembers set password='%s' where email='%s'", sqlEscapeString(encPwd), sqlEscapeString(email)); sqlUpdate(conn, query); hPrintf ( "<h2>UCSC Genome Browser</h2>" "<p align=\"left\">" "</p>" "<h3>Password has been changed.</h3>" "Click <a href=hgLogin?hgLogin.do.signupPage=1>here</a> to return.<br>" ); updatePasswordsFile(conn); @@ -507,30 +480,92 @@ cartRemove(cart, "hgLogin_password"); cartRemove(cart, "hgLogin_newPassword"); } void signupPage(struct sqlConnection *conn) /* draw the signup page */ /* XXXX TODO: cornfirm password, password help like Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only. optional real name */ { + +hPrintf( +"<div id=\"signUpBox\" class=\"centeredContainer formBox\">" +"<h2>UCSC Genome Browser</h2>" +"\n" +"<p>Signing up enables you to save multiple sessions and to share your sessions with others.</p>" +"Already have an account? <a href=\"hgLogin?hgLogin.do.displayLoginPage=1\">Login</a>.<br>" +"\n" +); +hPrintf( +"<h3>Sign Up</h3>" +"<form method=\"post\" action=\"hgLogin\" name=\"mainForm\">" +//"<div id=\"errorBox\" class=\"highlightBox error\">" +//" <span id=\"icon\"></span> <span id=\"message\">%s</span>" +//"</div>" +"<span style='color:red;'>%s</span>" +"\n" +, errMsg ? errMsg : "" +); +hPrintf( +"<div class=\"inputGroup\">" +"<label for=\"userName\">Username</label>" +"<input type=text name=\"hgLogin_userName\" value=\"%s\" size=\"30\" id=\"userName\">" +"</div>" +"\n" +"<div class=\"inputGroup\">" +"<label for=\"emailAddr\">Email address</label>" +"<input type=text name=\"hgLogin_email\" value=\"%s\" size=\"30\" id=\"emailAddr\">" +"</div>" +"\n" +"<div class=\"inputGroup\">" +"<label for=\"reenterEmail\">Re-enter Email address</label>" +"<input type=text name=\"hgLogin_email2\" value=\"%s\" size=\"30\" id=\"emailCheck\">" +"</div>" +"\n" +, cartUsualString(cart, "hgLogin_userName", "") +, cartUsualString(cart, "hgLogin_email", "") +, cartUsualString(cart, "hgLogin_email2", "") +); +hPrintf( +"<div class=\"inputGroup\">" +"<label for=\"password\">Password <small>(must be at least 5 characters)</small></label>" +"<input type=password name=\"hgLogin_password\" value=\"%s\" size=\"30\" id=\"password\">" +"</div>" +"\n" +"<div class=\"inputGroup\">" +"<label for=\"password\">Re-enter Password</label>" +"<input type=password name=\"hgLogin_password2\" value=\"%s\" size=\"30\" id=\"passwordCheck\">" +"\n" +"</div>" +"\n" +"<div class=\"formControls\">" +" <input type=\"submit\" name=\"hgLogin.do.signup\" value=\"Sign Up\" class=\"largeButton\"> " +" <a href=\"javascript:history.go(-1)\">Cancel</a>" +"</div>" +"</form>" +"</div><!-- END - signUpBox -->" +"\n" +, cartUsualString(cart, "hgLogin_password", "") +, cartUsualString(cart, "hgLogin_password2", "") +); +/******************************* old UI to be removed hPrintf( "<div id=\"hgLoginSignupBox\" class=\"centeredContainer\">\n" "<h2>UCSC Genome Browser</h2>" "\n" ); printf( "<P>" "Signing in enables you to save current settings into a " "named session, and then restore settings from the session later.<BR> " "If you wish, you can share named sessions with other users. " "</P>" ); hPrintf( @@ -552,186 +587,156 @@ " for=\"userName\">User Name</label>" "\n" "<input type=text name=\"hgLogin_user\" value=\"%s\" size=\"30\" id=\"userName\"> <br>" "\n" "<label style=\"display: block; margin-top: 10px;\" " " for=\"emailAddr\">E-mail</label>" "\n" "<input type=text name=\"hgLogin_email\" value=\"%s\" size=\"30\" id=\"emailAddr\"> <br>" "\n" "<label style=\"display: block; margin-top: 10px;\" " " for=\"password\">Password</label>" "\n" "<input type=password name=\"hgLogin_password\" value=\"%s\" size=\"30\" id=\"password\">" "\n" "<label style=\"display: block; margin-top: 10px;\" " -" for=\"confirmPW\">Confirm Password</label>" +" for=\"password2\">Confirm Password</label>" "\n" -"<input type=password name=\"hgLogin_confirmPW\" value=\"%s\" size=\"30\" id=\"confirmPW\">" +"<input type=password name=\"hgLogin_password2\" value=\"%s\" size=\"30\" id=\"password2\">" "\n" "<label style=\"display: block; margin-top: 10px;\" " " for=\"realName\">Real Name (optional)</label>" "\n" "<input type=text name=\"hgLogin_realName\" value=\"%s\" size=\"30\" id=\"realName\"> <br>" "\n" -/******** -"<tr><td>Name</td><td><input type=text name=hgLogin_user value=\"%s\" size=20></td></tr>\n" -"<tr><td>E-mail</td><td><input type=text name=hgLogin_email value=\"%s\"size=20>\n" -"<tr><td>Password</td><td><input type=password name=hgLogin_password value=\"%s\" size=10></td></tr>\n" -"<tr><td>Real name (optional)</td><td><input type=text name=hgLogin_realName value=\"%s\" size=20></td></tr>\n" -"<tr><td> </td><td><input type=submit name=hgLogin.do.signup value=submit>" -" <input type=button value=cancel ONCLICK=\"history.go(-1)\"></td></tr>\n" -"<br>\n" -, cartUsualString(cart, "hgLogin_user", "") -, cartUsualString(cart, "hgLogin_email", "") -//, cartUsualString(cart, "hgLogin_password", "") -, cartUsualString(cart, "hgLogin_realName", "") -); -****************/ "<p>" "<tr><td> </td><td><input type=submit name=hgLogin.do.signup value=submit>" " <input type=button value=cancel ONCLICK=\"history.go(-1)\"></td></tr>\n" "<br>\n" "</p>" -, cartUsualString(cart, "hgLogin_user", "") -, cartUsualString(cart, "hgLogin_email", "") -, cartUsualString(cart, "hgLogin_password", "") -, cartUsualString(cart, "hgLogin_confirmPW", "") -, cartUsualString(cart, "hgLogin_realName", "") -); - +****************************** to be removed ****************/ +// , cartUsualString(cart, "hgLogin_userName", "") +// , cartUsualString(cart, "hgLogin_email", "") +// , cartUsualString(cart, "hgLogin_email2", "") +// , cartUsualString(cart, "hgLogin_password", "") +// , cartUsualString(cart, "hgLogin_password2", "") +// ); +// cartSaveSession(cart); hPrintf("</FORM>"); } void signup(struct sqlConnection *conn) /* process the signup form */ { char query[256]; -char *user = cartUsualString(cart, "hgLogin_user", ""); +char *user = cartUsualString(cart, "hgLogin_userName", ""); if (!user || sameString(user,"")) { freez(&errMsg); errMsg = cloneString("User name cannot be blank."); signupPage(conn); return; } safef(query,sizeof(query), "select password from gbMembers where userName='%s'", user); char *password = sqlQuickString(conn, query); if (password) { freez(&errMsg); errMsg = cloneString("A user with this name already exists."); signupPage(conn); freez(&user); return; } char *email = cartUsualString(cart, "hgLogin_email", ""); if (!email || sameString(email,"")) { freez(&errMsg); errMsg = cloneString("Email cannot be blank."); signupPage(conn); return; } -password = cartUsualString(cart, "hgLogin_password", ""); -if (!password || sameString(password,"") || (strlen(password)<8)) +char *email2 = cartUsualString(cart, "hgLogin_email2", ""); +if (!email2 || sameString(email2,"")) { freez(&errMsg); - errMsg = cloneString("Password must be at least 8 characters long."); + errMsg = cloneString("Email cannot be blank."); signupPage(conn); return; } -if (!checkPwdCharClasses(password)) + +if (email && email2 && !sameString(email, email2)) { freez(&errMsg); - errMsg = cloneString("Password must contain characters from 2 of the following 4 classes: [A-Z] [a-z] [0-9] [!@#$%^&*()]."); + errMsg = cloneString("Email addresses do not match."); signupPage(conn); return; } -char *confirmPW = cartUsualString(cart, "hgLogin_confirmPW", ""); -if (!confirmPW || sameString(confirmPW,"") ) +password = cartUsualString(cart, "hgLogin_password", ""); +if (!password || sameString(password,"") || (strlen(password)<5)) { freez(&errMsg); - errMsg = cloneString("Confirm Password cannot be blank."); + errMsg = cloneString("Password must be at least 5 characters long."); signupPage(conn); return; } -if (password && confirmPW && !sameString(password, confirmPW)) + +char *password2 = cartUsualString(cart, "hgLogin_password2", ""); +if (!password2 || sameString(password2,"") ) { freez(&errMsg); - errMsg = cloneString("Passwords do not match."); + errMsg = cloneString("Password field cannot be blank."); signupPage(conn); return; } - -char *realName = cartUsualString(cart, "hgLogin_realName", ""); -if (!realName || sameString(realName,"")) +if (password && password2 && !sameString(password, password2)) { - realName = " "; + freez(&errMsg); + errMsg = cloneString("Passwords do not match."); + signupPage(conn); + return; } +/* pass all the checks, OK to create the account now */ char encPwd[45] = ""; encryptNewPwd(password, encPwd, sizeof(encPwd)); safef(query,sizeof(query), "insert into gbMembers set " - "userName='%s',realName='%s',password='%s',email='%s', " + "userName='%s',password='%s',email='%s', " "lastUse=NOW(),activated='N',dateAuthenticated='9999-12-31 23:59:59'", - sqlEscapeString(user),sqlEscapeString(realName),sqlEscapeString(encPwd),sqlEscapeString(email)); + sqlEscapeString(user),sqlEscapeString(encPwd),sqlEscapeString(email)); sqlUpdate(conn, query); hPrintf( "<h2>UCSC Genome Browser</h2>\n" "<p align=\"left\">\n" "</p>\n" "<h3>User %s successfully added.</h3>\n" , user ); - -backToHgSession(1); -/* -char *hgLoginHost = hgLoginLinkHost(); - -hPrintf( -"<script language=\"JavaScript\">\n" -"<!-- " -"\n" -"window.setTimeout(afterDelay, 1000);\n" -"function afterDelay() {\n" -"window.location =\"http://%s/cgi-bin/hgSession?hgS_doMainPage=1\";" -"\n}" -"\n" -"//-->" -"\n" -"</script>" -,hgLoginHost); -*/ - -//hPrintf( -//"Click <a href=hgLogin?hgLogin.do.signupPage=1>here</a> to return.<br>\n" -//); - +/* TODO: cleanup the hgLogin_xxxx vars in the cart */ +backToHgSession(3); } /* ----- account login/display functions ---- */ void displayLoginPage(struct sqlConnection *conn) /* draw the account login page */ { char *username = cartUsualString(cart, "hgLogin_userName", ""); /* for password security, use cgi hash instead of cart */ // char *password = cgiUsualString("hgLogin_password", ""); @@ -756,31 +761,31 @@ "\n" "<div class=\"inputGroup\">" "<label for=\"password\">Password</label>" "<input type=password name=\"hgLogin_password\" value=\"\" size=\"30\" id=\"password\">" "</div>" "\n" "<div class=\"formControls\">" " <input type=\"submit\" name=\"hgLogin.do.displayLogin\" value=\"Login\" class=\"largeButton\">" " <a href=\"javascript:history.go(-1)\">Cancel</a>" "</div>" "</form>" "\n" "\n" "<div id=\"helpBox\">" "<a href=\"accounthelp.html\">Can't access your account?</a><br>" -"Need an account? <a href=\"signupScreen.html\">Sign up</a>." +"Need an account? <a href=\"hgLogin?hgLogin.do.signupPage=1\">Sign up</a>." "</div><!-- END - helpBox -->" "</div><!-- END - loginBox -->" "\n" "\n" "</body>" "</html>" , username ); cartSaveSession(cart); } @@ -817,116 +822,101 @@ freez(&errMsg); char temp[256]; safef(temp,sizeof(temp),"User name %s not found.",userName); errMsg = cloneString(temp); displayLoginPage(conn); return; } struct gbMembers *m = gbMembersLoad(row); sqlFreeResult(&sr); /* TODO: check user name exist and activated */ /* ..... */ if (checkPwd(password,m->password)) { -hPrintf("<h1>Login succesful !!!! calling displayLoginSuccess now.</h1>\n"); unsigned int userID=m->idx; - // hPrintf("Before call userID is %d\n",userID); + hPrintf("<h2>Login successful for user %s with id %d.\n</h2>\n" + ,userName,userID); displayLoginSuccess(userName,userID); return; } else { //hPrintf("<h1>Invalid User/Password</h1>\n"); errMsg = cloneString("Invalid User/Password."); displayLoginPage(conn); // hPrintf("Return to <a href=\"hgLogin\">signup</A>.<br>\n"); return; } gbMembersFree(&m); } -/******* end old dispalyLogin *************************/ - - - +/******* END dispalyLogin *************************/ void displayLoginSuccess(char *userName, int userID) /* display login success msg, and set cookie */ { -char *hgLoginHost = hgLoginLinkHost(); +// char *hgLoginHost = hgLoginLinkHost(); hPrintf( "<h2>UCSC Genome Browser</h2>" "<p align=\"left\">" "</p>" "<span style='color:red;'></span>" "\n" ); +/* Set cookies */ +/* TODO: use htmlSetCookie() to set cookies */ hPrintf( "<script language=\"JavaScript\">" " document.write(\"Login successful, setting cookies now...\");" -" document.write(\" in Call userID is %d\n\");" "</script>\n" "<script language=\"JavaScript\">" "document.cookie = \"hgLogin_UserName=%s; domain=ucsc.edu; expires=Thu, 31 Dec 2099, 20:47:11 UTC; path=/\"; " "\n" "document.cookie = \"hgLogin_UserID=%d; domain=ucsc.edu; expires=Thu, 31 Dec 2099, 20:47:11 UTC; path=/\";" " </script>" "\n", -userID, userName,userID); -hPrintf( -"<script language=\"JavaScript\">\n" -"<!-- " -"\n" -/* delay for 5 seconds then go back to page X */ -/* TODO: afterDelayBackTo("http....") */ -"window.setTimeout(afterDelay, 1000);\n" -"function afterDelay() {\n" -"window.location =\"http://%s/cgi-bin/hgSession?hgS_doMainPage=1\";" -"\n}" -"\n" -"//-->" -"\n" -"</script>" -,hgLoginHost); +userName,userID); +backToHgSession(5); } void displayLogoutSuccess() /* display logout success msg, and reset cookie */ { // char *hgLoginHost = hgLoginLinkHost(); hPrintf( "<h2>UCSC Genome Browser Sign Out</h2>" "<p align=\"left\">" "</p>" "<span style='color:red;'></span>" "\n" ); hPrintf( "<script language=\"JavaScript\">" "document.cookie = \"hgLogin_UserName=; domain=ucsc.edu; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/\"; " "\n" "document.cookie = \"hgLogin_UserID=; domain=ucsc.edu; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/\";" "</script>\n" ); +/* TODO: cleanup the hgLogin_xxxx vars in the cart */ /* return to session */ backToHgSession(1); } void backToHgSession(int nSec) /* delay for N micro seconds then go back to hgSession page */ /* TODO: afterDelayBackTo("http....") */ { char *hgLoginHost = hgLoginLinkHost(); int delay=nSec*1000; hPrintf( "<script language=\"JavaScript\">\n" "<!-- " "\n" @@ -937,31 +927,31 @@ "\n}" "\n" "//-->" "\n" "</script>" ,delay ,hgLoginHost); } void displayUserInfo(struct sqlConnection *conn) /* display user account info */ { struct sqlResult *sr; char **row; char query[256]; -char *user = cartUsualString(cart, "hgLogin_user", ""); +char *user = cartUsualString(cart, "hgLogin_userName", ""); /*************************************/ if (sameString(user,"")) { freez(&errMsg); errMsg = cloneString("User name cannot be blank."); displayUserInfo(conn); return; } /* for password security, use cgi hash instead of cart */ char *password = cgiUsualString("hgLogin_password", ""); if (sameString(password,"")) { freez(&errMsg); errMsg = cloneString("Password cannot be blank."); displayUserInfo(conn); @@ -995,70 +985,30 @@ hPrintf("Return to <a href=\"hgLogin\">signup</A>.<br>\n"); hPrintf("Go to <a href=\"/\">UCSC Genome Browser</A>.<br>\n"); } else { hPrintf("<h1>Invalid User/Password</h1>\n"); hPrintf("Return to <a href=\"hgLogin\">signup</A>.<br>\n"); } /**************************************************/ gbMembersFree(&m); } -/* -void upgradeMembersTable(struct sqlConnection* conn) -/ * one-time upgrade of gbMembers table to store encrypted passwords * / -{ -char query[256]; - -safef(query,sizeof(query),"select email from members"); -struct slName *email=NULL,*list = sqlQuickList(conn,query); -for(email=list;email;email=email->next) - { - - uglyf("email=%s<br>\n",email->name); - - safef(query,sizeof(query),"select password from gbMembers where email='%s'", email->name); - char *password = sqlQuickString(conn,query); - - uglyf("password=%s<br>\n",password); - - if (password) - { - if (!startsWith("$1$",password)) / * upgrade has not already been done * / - { - uglyf("does not start with $1$<br>\n"); - char encPwd[45] = ""; - encryptNewPwd(password, encPwd, sizeof(encPwd)); - safef(query,sizeof(query),"update gbMembers set password = '%s' where email='%s'", - sqlEscapeString(encPwd), sqlEscapeString(email->name)); - uglyf("query: %s<br>\n",query); - sqlUpdate(conn,query); - } - freez(&password); - } - - uglyf("<br>\n"); - - } -slFreeList(&list); -} -*/ - void doMiddle(struct cart *theCart) /* Write the middle parts of the HTML page. * This routine sets up some globals and then * dispatches to the appropriate page-maker. */ { struct sqlConnection *conn = hConnectCentral(); cart = theCart; if (cartVarExists(cart, "debug")) debugShowAllMembers(conn); /* remove after a while when it is no longer needed else if (cartVarExists(cart, "fixMembers")) {