public void Push(ParameterStorage nParam) { foreach (var key in nParam.Parameters.Keys) { Push(key, nParam[key]); } }
internal static async Task <ParameterStorage> GetLoginParameterAsync(string script) { return(await Task.Run(() => { ParameterStorage retVal = new ParameterStorage(); Match frmData = Regex.Match(script, "name:\"(.*?)\", value:\"(.*?)\""); if (frmData.Success) { retVal.Push(frmData.Groups[1].Value, frmData.Groups[2].Value); } else { throw new Exception("스크립트 파싱에 실패하였습니다."); } return retVal; })); }
internal static async Task <Tuple <string, ParameterStorage> > GetDeleteGalleryArticleParameterAsync(string script, GalleryType gallType) { return(await Task.Run(() => { string encCode = null; ParameterStorage storage = new ParameterStorage(); #if false Match encData = Regex.Match(script, "var _r = _d\\(\'(.*)\'\\)"); #else Match encData = null; throw new Exception("알 수 없는 오류가 발생했습니다."); #endif if (encData.Success) { encCode = encData.Groups[1].Value; } else { if (gallType == GalleryType.Normal) { throw new Exception("자바스크립트 파싱에 실패하였습니다."); } } Match frmData = Regex.Match(script, "formData \\+= \"&(.*)=(.*)\";"); if (frmData.Success) { storage.Push(frmData.Groups[1].Value, frmData.Groups[2].Value); } else { throw new Exception("자바스크립트 파싱에 실패하였습니다."); } return new Tuple <string, ParameterStorage>(encCode, storage); })); }
private async Task <DeleteResult> PostDeleteMinorGalleryFlowArticleAsync(GalleryArticleDeleteParameter delParam, string key) { string pageHtml = await GetDeleteGalleryArticlePageAsync(delParam.GalleryId, delParam.ArticleID, key, GalleryType.Minor); Tuple <ParameterStorage, string> parseResult; ParameterStorage delete_Params = null; try { parseResult = await HtmlParser.GetDeleteFlowArticleParameterAsync(pageHtml, GalleryType.Minor); } catch (Exception e) { return(new DeleteResult(false, e.Message)); } delete_Params = parseResult.Item1; string reqURL = _galleryURL + "/mgallery/forms/delete_submit"; string referer = _galleryURL + "/mgallery/board/delete/?id=" + delParam.GalleryId + "&no=" + delParam.ArticleID + "&key=" + key; using (HttpClientHandler handler = new HttpClientHandler() { CookieContainer = cookies }) using (HttpClient client = new HttpClient(handler)) { client.DefaultRequestHeaders.Accept.ParseAdd(_defaultAcceptString); client.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest"); client.DefaultRequestHeaders.Referrer = new Uri(referer); client.DefaultRequestHeaders.UserAgent.ParseAdd(_userAgent); client.Timeout = new TimeSpan(0, 0, 0, 0, _defaultTimeout); string reqData = delete_Params.ToString(); using (HttpResponseMessage res = await client.PostAsync(reqURL, new StringContent(reqData, Encoding.UTF8, "application/x-www-form-urlencoded"))) { res.EnsureSuccessStatusCode(); using (HttpContent content = res.Content) { string result = await content.ReadAsStringAsync(); if (result.StartsWith("true||" + delParam.GalleryId)) { return(new DeleteResult(true, "")); } else if (result == "false||비밀번호 인증에 실패하였습니다. 다시 시도해주세요" || result == "false|| 비밀번호가 맞지 않습니다. 다시 시도해주세요" || result == "false||비밀번호가 잘못되었습니다. 다시 시도해주세요") { return(new DeleteResult(false, "비밀번호가 다릅니다.")); } else { return(new DeleteResult(false, "알 수 없는 오류입니다.")); } } } } }
private async Task <DeleteResult> PostDeleteGalleryFlowArticleAsync(GalleryArticleDeleteParameter delParam, GalleryType gallType, int delay) { string pageHtml = await GetDeleteGalleryArticlePageAsync(delParam.GalleryId, delParam.ArticleID, null, gallType); Tuple <ParameterStorage, string> parseResult; ParameterStorage delete_Params = null; string lately_gallery = null; try { parseResult = await HtmlParser.GetDeleteFlowArticleParameterAsync(pageHtml, gallType); } catch (Exception e) { return(new DeleteResult(false, e.Message)); } delete_Params = parseResult.Item1; lately_gallery = parseResult.Item2; if (gallType == GalleryType.Normal) { cookies.Add(new Cookie("lately_cookie", HttpUtility.UrlEncode(lately_gallery)) { Domain = "dcinside.com" }); } await Task.Delay(delay); string reqURL = null; string referer = null; if (gallType == GalleryType.Normal) { reqURL = _galleryURL + "/forms/delete_password_submit"; referer = _galleryURL + "/board/delete/?id=" + delParam.GalleryId + "&no=" + delParam.ArticleID; } else if (gallType == GalleryType.Minor) { reqURL = _galleryURL + "/mgallery/forms/delete_password_submit"; referer = _galleryURL + "/mgallery/board/delete/?id=" + delParam.GalleryId + "&no=" + delParam.ArticleID; } if (reqURL == null || referer == null) { throw new Exception("예상치 못한 갤러리 형식입니다."); } using (HttpClientHandler handler = new HttpClientHandler() { CookieContainer = cookies }) using (HttpClient client = new HttpClient(handler)) { client.DefaultRequestHeaders.Accept.ParseAdd(_defaultAcceptString); client.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest"); client.DefaultRequestHeaders.Referrer = new Uri(referer); client.DefaultRequestHeaders.UserAgent.ParseAdd(_userAgent); client.Timeout = new TimeSpan(0, 0, 0, 0, _defaultTimeout); string reqData = delete_Params.ToString(); reqData += "&password="******"application/x-www-form-urlencoded"))) { res.EnsureSuccessStatusCode(); using (HttpContent content = res.Content) { string result = await content.ReadAsStringAsync(); if (result.StartsWith("true||")) { if (gallType == GalleryType.Normal) { return(new DeleteResult(true, "")); } else { return(await PostDeleteMinorGalleryFlowArticleAsync(delParam, result.Replace("true||", ""))); } } else if (result == "false||비밀번호 인증에 실패하였습니다. 다시 시도해주세요" || result == "false|| 비밀번호가 맞지 않습니다. 다시 시도해주세요" || result == "false||비밀번호가 잘못되었습니다. 다시 시도해주세요") { return(new DeleteResult(false, "비밀번호가 다릅니다.")); } else { return(new DeleteResult(false, "알 수 없는 오류입니다.")); } } } } }
private async Task <LoginStatus> PostLoginAsync(string id, string pw, bool retry = true) { string gallUrl = "gallog"; string gallogUrl = _gallogURL + "/" + id; string referer = _loginPageURL + "?s_url=" + HttpUtility.UrlEncode(gallUrl); LoginStatus status = new LoginStatus(); // 로그인 페이지에 한번은 접속해야 정상 동작함 string loginPageSrc = await GetLoginPageAsync(gallUrl); if (loginPageSrc.Contains("로그인 되었습니다")) { status = LoginStatus.Success; return(status); } ParameterStorage LoginParams = await HtmlParser.GetLoginParameterAsync(loginPageSrc); using (HttpClientHandler handler = new HttpClientHandler() { CookieContainer = cookies }) using (HttpClient client = new HttpClient(handler)) { client.DefaultRequestHeaders.Accept.ParseAdd(_defaultAcceptString); client.DefaultRequestHeaders.Referrer = new Uri(referer); client.DefaultRequestHeaders.UserAgent.ParseAdd(_userAgent); client.Timeout = new TimeSpan(0, 0, 0, 0, _defaultTimeout); string param = "s_url=" + HttpUtility.UrlEncode(gallUrl) + "&tieup=&url=&user_id=" + id + "&password="******"&x=0&y=0&ssl_chk=on&"; param += LoginParams.ToString(); using (HttpResponseMessage res = await client.PostAsync(_loginURL, new StringContent(param, Encoding.UTF8, "application/x-www-form-urlencoded"))) { res.EnsureSuccessStatusCode(); using (HttpContent content = res.Content) { string result = await content.ReadAsStringAsync(); if (result.Contains("등록된 아이디가 아닙니다.")) { status = LoginStatus.IDError; } else if (result.Contains("비밀번호가 틀렸습니다.")) { status = LoginStatus.PasswordError; } else if (result.Contains("아이디 또는 비밀번호가 잘못되었습니다.")) { status = LoginStatus.ErrorBoth; } else if (result.Contains("로그인을 5번 실패 하셨습니다.")) { status = LoginStatus.MaximumAttemptFailed; } else if (result.Contains("잘못된 접근입니다")) { status = LoginStatus.Unknown; } else if (result.Contains(gallogUrl)) { status = LoginStatus.Success; } else { status = LoginStatus.Unknown; } if (retry) { return(await PostLoginAsync(id, pw, false)); } } } } return(status); }
/// <summary> /// 삭제할 글의 파라미터를 가져오는 함수 /// </summary> /// <param name="html">글 삭제 페이지의 HTML 소스</param> /// <param name="gallType">갤러리 구분</param> /// <param name="delete_Params">글 삭제에 필요한 파라미터</param> /// <param name="lately_gallery">최근 방문한 갤러리</param> internal static async Task <Tuple <ParameterStorage, string> > GetDeleteArticleParameterAsync(string html, GalleryType gallType) { return(await Task.Run(async() => { string lately_gallery = null; ParameterStorage delete_Params = new ParameterStorage(); HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(html); HtmlNode deleteNode = null; try { deleteNode = doc.GetElementbyId("id").ParentNode.SelectSingleNode(".//form"); lately_gallery = doc.GetElementbyId("lately_gallery").GetAttributeValue("value", ""); } catch { } // 삭제 노드가 없는 경우 이미 삭제된 글이거나 오류 if (deleteNode == null) { if (html.Contains("/error/deleted")) { throw new Exception("이미 삭제된 글입니다."); } else if (doc.GetElementbyId("password_confirm") != null) { throw new Exception("이미 삭제된 글입니다."); } else { throw new Exception("알 수 없는 오류입니다."); } } // 회원글인데 비밀번호 입력하는 페이지인 경우 이미 삭제된 글 if (deleteNode.Attributes["action"].Value.Contains("delete_password_submit")) { throw new Exception("이미 삭제된 글입니다."); } foreach (HtmlNode input in deleteNode.ParentNode.Descendants("input").Where(n => n.GetAttributeValue("type", "") == "hidden")) { delete_Params.Push(input.GetAttributeValue("name", ""), input.GetAttributeValue("value", "")); } string jsEncCode; ParameterStorage jsParam; string jsScript = ""; foreach (HtmlNode scriptNode in doc.DocumentNode.Descendants("script")) { jsScript += scriptNode.InnerHtml; } if (jsScript == "") { throw new Exception("알 수 없는 오류입니다."); } // 글 삭제시 실행되는 스크립트의 추가 값을 가져옴 var parseResult = await JSParser.GetDeleteGalleryArticleParameterAsync(jsScript, gallType); jsEncCode = parseResult.Item1; jsParam = parseResult.Item2; delete_Params.Push(jsParam); if (gallType == GalleryType.Normal) { delete_Params["service_code"] = Cryption.DecryptCode(jsEncCode, delete_Params["service_code"]); } return new Tuple <ParameterStorage, string>(delete_Params, lately_gallery); })); }