/// <summary> /// Gets credentials for an online reader. /// </summary> /// <param name="readerName"></param> /// <returns></returns> public static OnlineCredentials GetCredentials( string filename, string serviceName ) { var xmlCredentials = new XmlDocument(); xmlCredentials.Load( filename ); OnlineCredentials credentials = new OnlineCredentials(); foreach( XmlNode node in xmlCredentials.SelectNodes( "/credentials/service" ) ) { if( node.Attributes["name"].Value.ToLower() == serviceName.ToLower() ) { bool encrypted = false; if( node.Attributes["encrypted"] != null ) encrypted = Convert.ToBoolean( node.Attributes["Encrypted"].Value ); // Found matching Reader node foreach( XmlNode childNode in node.ChildNodes ) { if( childNode.Name.ToLower() == "add" ) { credentials.Add( childNode.Attributes["key"].Value, childNode.Attributes["value"].Value ); } } } } return credentials; }
public Downloader( IDataProvider dataStorage, IOnlineService service, OnlineCredentials credentials ) { // TODO: Convert to Microsoft Code Contracts //Assert.PreCondition( dataStorage != null ); //Assert.PreCondition( service != null ); //Assert.PreCondition( credentials != null ); this.dataStorage = dataStorage; this.credentials = credentials; this.service = service; }
public override void Connect( OnlineCredentials credentials ) { base.Connect( credentials ); this.credentials = credentials; // Load initial page to establish a session string html; string baseUri = "https://secure.ingdirect.com"; this.LogWrite( OnlineServiceEventType.Service, "Connecting to web site" ); // Login html = this.browser.HttpGet( baseUri + "/myaccount/INGDirect/login.vm?device=web&locale=en_US&userType=Client" ); this.LogWrite( OnlineServiceEventType.Service, "Sending username" ); // Populate form fields, including hidden fields // This information was obtained by examining the HTML on the login page NameValueCollection fields = new NameValueCollection(); fields.Add( "Locale", "en_US" ); fields.Add( "Device", "web" ); fields.Add( "UserType", "Client" ); fields.Add( "AuthenticationType", "Primary" ); fields.Add( "ApplicationType", "ViewAccount" ); fields.Add( "DeviceToken", "" ); fields.Add( "fp_browser", "" ); fields.Add( "fp_screen", "" ); fields.Add( "fp_software", "" ); fields.Add( "from", "NewPage" ); fields.Add( "pm_fp", "" ); fields.Add( "publicUserId", credentials.Username ); fields.Add( "_rememberMyCIF", "" ); fields.Add( "pageType", "primary" ); fields.Add( "eva", "" ); html = this.browser.HttpPostForm( baseUri + "/myaccount/INGDirect/login.vm", fields, true ); // Check for security questions page if( html.IndexOf( "you'll need to answer 2 of your security questions" ) >= 0 ) { this.LogWrite( OnlineServiceEventType.Service, "Sending security responses" ); // <form action="security_questions.vm" name="CustomerAuthenticate" method="POST" title="Sign In" id="CustomerAuthenticate" class="m_proxy" onkeypress="checkEnter(event, this);"> fields.Clear(); fields.Add( "AlternateQuestionsSource", "empty" ); fields.Add( "isacif", "true" ); fields.Add( "QuestionHelp", "" ); fields.Add( "TLSearchNum", credentials.Username ); // HACK: Assumes both security answers are the same fields.Add( "customerAuthenticationResponse.questionAnswer[0].answerText", credentials["Response1"] ); fields.Add( "customerAuthenticationResponse.questionAnswer[1].answerText", credentials["Response2"] ); fields.Add( "hidetyping", "false" ); fields.Add( "_customerAuthenticationResponse.device[0].bind", "false" ); fields.Add( "customerAuthenticationResponse.device[0].bind", "true" ); fields.Add( "YES, I WANT TO CONTINUE.", "true" ); html = this.browser.HttpPostForm( baseUri + "/myaccount/INGDirect/security_questions.vm", fields, true ); } // Password this.LogWrite( OnlineServiceEventType.Service, "Sending password" ); // ING does a very odd thing with the password (or PIN) entry. // Normally, you have to click the keypad on the page to enter // the numbers, but they have an alternate "keyboard" entry // where you key in letters that correspond to the digits // on the keypad. The thing is, the letters that you press // are different each time, so you have to sniff out which // letters they have assigned to each digit. It's a massive // pain in the butt but it doesn't do anything to prevent // a persistent programmer from scraping their data. // We can tell the letters they use by the names of the images displayed. MatchCollection matches = Regex.Matches( html, "<img src=\"https://images.ingdirect.com/images/secure/pinpad/([ABCDEFGHIJKLMNOPQRSTUVWXYZ]).gif\"" ); // There should be exactly ten matches: 123 456 789 0 if( matches.Count != 10 ) throw new OnlineServiceException( "Unexpected number of PIN images - scraper may need updating" ); // Build an array mapping the letters to numbers // (Move the 0 from the end to the beginning of the array.) Dictionary<string, string> digitMapping = new Dictionary<string,string>(); for( int i = 0; i < 9; i++ ) digitMapping[(i+1).ToString()] = matches[i].Groups[1].Value; digitMapping[0.ToString()] = matches[9].Groups[1].Value; // Translate the user's password into letters StringBuilder sb = new StringBuilder(); foreach( char c in credentials.Password ) { if( !Char.IsDigit( c ) ) throw new OnlineServiceCredentialsException( "Password (PIN) must consist of numbers only" ); sb.Append( digitMapping[c.ToString()] ); } string mappedPassword = sb.ToString(); fields.Clear(); fields.Add( "customerAuthenticationResponse.PIN", mappedPassword ); fields.Add( "riskBasedAuthorizationResults", "" ); html = this.browser.HttpPostForm( baseUri + "/myaccount/INGDirect/login_pinpad.vm", fields, true ); if( html.IndexOf( "You've entered your PIN incorrectly. Please try again." ) >= 0 ) throw new OnlineServiceCredentialsException( "Invalid user ID or password" ); // Save the HTML for the Accounts getter below. this.accountHtml = html; }
public override void Connect( OnlineCredentials credentials ) { base.Connect( credentials ); this.LogWrite( OnlineServiceEventType.Service, "Logging in" ); string html = this.browser.HttpGet( "https://www.suntrust.com/portal/server.pt" ); string action = this.browser.RegexCapture( "<form method=\"post\" action=\"(https://.*?)\" name=\"lform\" id=\"loginFormID\" autocomplete=\"off\">", html ); // Populate form fields, including hidden fields // This information was obtained by examining the Suntrust HTML NameValueCollection fields = new NameValueCollection(); fields.Add( "in_hi_space", "Login" ); fields.Add( "in_hi_spaceID", "0" ); fields.Add( "in_hi_control", "Login" ); fields.Add( "in_hi_dologin", "false" ); // was "true" fields.Add( "uid", credentials.Username ); fields.Add( "password", credentials.Password ); fields.Add( "in_bu_Login", "Log In" ); html = this.browser.HttpPostForm( action, fields ); if( html.IndexOf( "The User ID and/or password you entered does not match our records" ) >= 0 ) throw new OnlineServiceCredentialsException( "The supplied credentials were rejected by the Suntrust site." ); // Verify that we got a page we expect. this.browser.RegexAssert( "Please wait while we validate your sign-on information", html ); // Now work our way through several redirect pages until we get to // the summary page. action = this.browser.RegexCapture( "<form name=\"Form1_442\" method=\"post\" action=\"(.*?)\"", html ); fields.Clear(); fields.Add( "__EVENTTARGET", "phasedControl:cmdSubmitDeviceInfo" ); fields.Add( "__EVENTARGUMENT", this.browser.RegexCapture( "<input type=\"hidden\" name=\"__EVENTARGUMENT\" id=\"__EVENTARGUMENT\" value=\"(.*?)\" />", html ) ); fields.Add( "__VIEWSTATE", this.browser.RegexCapture( "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"(.*?)\" />", html ) ); fields.Add( "phasedControl:mfBrowserCookies", this.browser.CookieText ); // Hardcoded: fields.Add( "phasedControl:mfDevicePrint", "version=1&pm_fpua=mozilla/5.0 (windows; u; windows nt 6.0; en-us; rv:1.9.0.8) gecko/2009032609 firefox/3.0.8 (.net clr 3.5.30729)|5.0 (Windows; en-US)|Win32&pm_fpsc=32|1680|1050|1020&pm_fpsw=|qt6|qt5|qt4|qt3|qt2|qt1|def|swf|pdf&pm_fptz=-4&pm_fpln=lang=en-US|syslang=|userlang=&pm_fpjv=0&pm_fpco=1" ); // Hardcoded: fields.Add( "phasedControl:mfUserAgent", "mozilla/5.0 (windows; u; windows nt 6.0; en-us; rv:1.9.0.8) gecko/2009032609 firefox/3.0.8 (.net clr 3.5.30729)|5.0 (Windows; en-US)|Win32|en-US" ); // Note that Suntrust will return varying forms of the following // page depending on the settings provided in the form populated above. html = this.browser.HttpPostForm( action, fields ); action = this.browser.RegexCapture( @"window\.location\.replace\('(.*?)'\);", html ); html = this.browser.HttpGet( action ); action = this.browser.RegexCapture( "<meta HTTP-EQUIV=\"REFRESH\" CONTENT=\"0; URL=(.*?)\">", html ); html = this.browser.HttpGet( action ); action = "https://www.suntrust.com/portal/server.pt?" + this.browser.RegexCapture( @"window\.location=pt_533\.makeAbsoluteURL\(OpenerAS_GetApplicationBaseURL\(\) \+ ""(.*?)""\);", html ); // Finally we get to the actual summary page. this.summaryPageHtml = this.browser.HttpGet( action ); this.isLoggedIn = true; }
public override void Connect( OnlineCredentials credentials ) { base.Connect( credentials ); // Load initial page to establish a session string html; string baseVacuUri = "https://command.onlinebank.com/1899/"; this.LogWrite( OnlineServiceEventType.Service, "Connecting to VACU web site" ); // Home.aspx html = this.browser.HttpGet( baseVacuUri + "Home.aspx" ); // 4/23/2011 VACU changed the control container names (M$ to M$L$), // made regex more generalized. this.LogWrite( OnlineServiceEventType.Service, "Sending username" ); string action = this.browser.RegexCapture( "<form name=\"aspnetForm\" method=\"post\" action=\"(.*?)\"", html ); if( action == null || action.Length == 0 ) throw new OnlineServiceException( "Unable to locate form action URL." ); // Populate form fields, including hidden fields // This information was obtained by examining the HTML at the Vacu login page NameValueCollection fields = new NameValueCollection(); fields.Add( "M_content_ScriptManager_HiddenField", ";;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35:en-US:1247b7d8-6b6c-419f-a45f-8ff264c90734:ea597d4b:b25378d2" ); fields.Add( "UsePrinterFriendlyVersion", "Off" ); fields.Add( "__VIEWSTATEID", this.browser.DotNetCaptureHidden( html, "__VIEWSTATEID" ) ); fields.Add( "__VIEWSTATE", "" ); fields.Add( "__EVENTVALIDATION", this.browser.DotNetCaptureHidden( html, "__EVENTVALIDATION" ) ); foreach( Match match in Regex.Matches( html, @"<input name=""(.*?\$state)"" type=""hidden"" id="".*?_state"" />" ) ) fields.Add( match.Groups[1].Value, string.Empty ); fields.Add( this.browser.RegexCapture( @"<input name=""(.*?\$LoginName)"" type=""text""", html ), credentials.Username ); fields.Add( this.browser.RegexCapture( @"<input type=""submit"" name=""(.*?\$cmdContinue)"" value=""Continue""", html ), "1" ); // Post to Default.aspx html = this.browser.DotNetPostBack( baseVacuUri + action, fields, string.Empty, string.Empty ); // Password this.LogWrite( OnlineServiceEventType.Service, "Sending password." ); action = this.browser.RegexCapture( "<form name=\"aspnetForm\" method=\"post\" action=\"(.*?)\"", html ); if( action == null || action.Length == 0 ) throw new OnlineServiceException( "Unable to locate form action URL." ); fields.Clear(); fields.Add( "M_content_ScriptManager_HiddenField", ";;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35:en-US:1247b7d8-6b6c-419f-a45f-8ff264c90734:ea597d4b:b25378d2" ); fields.Add( "UsePrinterFriendlyVersion", "Off" ); fields.Add( "__EVENTTARGET", string.Empty ); fields.Add( "__EVENTARGUMENT", string.Empty ); fields.Add( "__VIEWSTATEID", this.browser.DotNetCaptureHidden( html, "__VIEWSTATEID" ) ); fields.Add( "__VIEWSTATE", string.Empty ); fields.Add( "__EVENTVALIDATION", this.browser.DotNetCaptureHidden( html, "__EVENTVALIDATION" ) ); foreach( Match match in Regex.Matches( html, @"<input name=""(.*?\$state)"" type=""hidden"" id="".*?_state"" />" ) ) fields.Add( match.Groups[1].Value, string.Empty ); fields.Add( this.browser.RegexCapture( @"<input name=""(.*?\$Password)"" type=""password""", html ), credentials.Password ); fields.Add( this.browser.RegexCapture( @"<input type=""submit"" name=""(.*?\$cmdContinue)"" value=""Sign in""", html ), "1" ); // Post to Password.aspx html = this.browser.HttpPostForm( baseVacuUri + "AOP/" + action, fields, true ); if( html.IndexOf( "Invalid user ID or password" ) >= 0 ) throw new OnlineServiceCredentialsException( "Invalid user ID or password" ); // TODO: Possible additional security questions // Look for keyword indicating page is asking for security question if( html.IndexOf( "For additional security, please provide your answers to the following questions." ) >= 0 ) { action = this.browser.RegexCapture( "<form name=\"aspnetForm\" method=\"post\" action=\"(.*?)\"", html ); if( action == null || action.Length == 0 ) throw new OnlineServiceException( "Unable to locate form action URL." ); string challengeQuestion = this.browser.RegexCapture( "<span id=\"M_content_.*?_ctl00_lblQuestion\">(.*?)</span>", html ); string challengeResponse = ""; this.LogWrite( OnlineServiceEventType.Service, "Responding to challenge question." ); if( challengeQuestion.IndexOf( credentials["Challenge1"] ) >= 0 ) challengeResponse = credentials["Response1"]; else if( challengeQuestion.IndexOf( credentials["Challenge2"] ) >= 0 ) challengeResponse = credentials["Response2"]; else if( challengeQuestion.IndexOf( credentials["Challenge3"] ) >= 0 ) challengeResponse = credentials["Response3"]; else throw new OnlineServiceException( "Unrecognized challenge question ('" + challengeQuestion + "'). Unable to respond." ); fields.Clear(); fields.Add( "M_content_ScriptManager_HiddenField", ";;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35:en-US:1247b7d8-6b6c-419f-a45f-8ff264c90734:ea597d4b:b25378d2" ); fields.Add( "UsePrinterFriendlyVersion", "Off" ); fields.Add( "__VIEWSTATEID", this.browser.DotNetCaptureHidden( html, "__VIEWSTATEID" ) ); fields.Add( "__VIEWSTATE", "" ); fields.Add( "__EVENTVALIDATION", this.browser.DotNetCaptureHidden( html, "__EVENTVALIDATION" ) ); fields.Add( "M$content$PCDZ$M3WO5TB$ctl00$rptAnswerQuestions$ctl00$txtAnswer", challengeResponse ); fields.Add( "M$content$PCDZ$M3WO5TB$ctl00$cmdSubmit", "1" ); html = this.browser.DotNetPostBack( baseVacuUri + "AOP/" + action, fields, string.Empty, string.Empty ); } this.visaLink = this.browser.RegexCapture( @"<a target=""_blank"" href=""\.\./(PSCU\.aspx.*?)"">", html ); // Summary Page }