论坛大大说要来一些技术方面的东西。
private async Task<bool> ShowKnowledgeBaseResultsAsync(
IDialogContext context,
LuisResult result,
BotMetric telemetryEvent,
bool needsMandatoryKeywords = true,
bool showFallbackResults = true,
bool notDisplayResults = false)
{
// check config if Bing is disabled, don't use it
showFallbackResults = showFallbackResults && this.AllowFallback;
var handled = false;
// azure index results - KB results and action link results
var search = Conversation.Container.Resolve<IKnowledgeBaseSearch>();
var knowledgeBaseResults = await search.GetLuisSearchAsync(result, telemetryEvent, needsMandatoryKeywords).ConfigureAwait(false);
if (knowledgeBaseResults.Records != null && knowledgeBaseResults.Records.Any())
{
List<KnowledgeBaseQuestionId> kbAnswers = new List<KnowledgeBaseQuestionId>();
foreach (var answer in knowledgeBaseResults.Records)
{
kbAnswers.Add(new KnowledgeBaseQuestionId(answer.QuestionId, answer.Score));
}
if (notDisplayResults)
{
var message = PackageChannelDataToMessage(context
, result
, knowledgeBaseResults.Records.First().Question
, configuration.LuisOptions.MinConfidence
, true
, kbAnswers);
await context.PostAsync(message).ConfigureAwait(false);
}
else
{
string subtitle;
var title = GetCardTitleDetails(result, out subtitle);
var displaySearchResult = new DisplaySearchResult(Telemetry);
var customChannelData = PackageCustomChannelData(result, kbAnswers, true, configuration.LuisOptions.MinConfidence);
await displaySearchResult
.DisplayKnowledgeBaseResultAsync(context, customChannelData, knowledgeBaseResults, title, subtitle)
.ConfigureAwait(false);
}
this.SendFeedbackForKbResult(context, result, knowledgeBaseResults.Records);
handled = true;
}
//else if (showFallbackResults)
//{
// // could be Bing or Too much KB
// var needBingResult = knowledgeBaseResults.Records != null || !knowledgeBaseResults.Records.Any(); // no results in KB
// if (needBingResult)
// {
// CustomChannelData customChannelData = new CustomChannelData
// {
// Luis = result,
// KBAnswers = null
// };
// var query = result.AlteredQuery ?? result.Query;
// handled = await this.ShowFallbackResultsAsync(context, customChannelData, query, telemetryEvent).ConfigureAwait(false);
// }
// else
// {
// telemetryEvent.Mark(
// TelemetryMetrics.BingResults,
// "END: Reverting to user as found too many answers in KB");
// }
// // Went to fallback, so handle missing KB
// await HandleMissingKnowledgeBase(telemetryEvent);
//}
return handled;
}
private async Task AskToRephraseAsync(IDialogContext context, LuisResult result, BotTelemetryEvent telemetryEvent)
{
var message = PackageChannelDataToMessage(context, result
, $"不好意思我不理解 **'{result.Query}'**. 您可以换一种说法么?"
, configuration.LuisOptions.MinConfidence);
await context.PostAsync(message).ConfigureAwait(false);
//await HandleMissingKnowledgeBase(telemetryEvent);
}
private static List<IntentRecommendation> GetSimilarIntents(LuisResult result, double luisMinConfidence = 0.5)
{
var similarIntentScore = result.TopScoringIntent.Score * 0.7;
return result.Intents.Where(x =>
(x.Score >= similarIntentScore
&& x.Score.Value >= luisMinConfidence)
|| x.Intent.Equals(result.TopScoringIntent.Intent, StringComparison.InvariantCultureIgnoreCase)).ToList();
}
因为保密协议的缘故,详细的技术实现无法写太多。。。
既然申请ID就贴一些符合主题的之前手边的小工具吧。
前公司制度规范每个工作日需要在公司论坛完成日常任务,与薪酬挂钩不得不重视。。。
简单分析一下登录地址:
member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes&inajax=1";
观察了一下,传统的form表单提交。
用代码来实现模拟登录然后完成发帖回复任务量。
用Postman初步尝试了一下。。返回:您当前的访问请求当中含有非法字符,已经被系统拒绝
检查了一下少了2个参数
quickforward=yes&handlekey=ls
再次提交还是一样的错误,什么鬼?再次检查发现对referer地址进行了验证。好吧,带上referer
这次提示信息变了,请输入验证码。
基于Discuz的验证码登录的话,通过观察与尝试发现在html隐藏了3个hidden属性的hash验证值。
看一下返回页面的html代码,一个叫loginhash,另外一个叫seccode_ ,最后一个叫formhash
通过正则拿出来
private string GetLoginHash(string html)
{
Match match = new Regex(";loginhash=(?'hash'.*?)\"", RegexOptions.None).Match(html);
return match.Groups["hash"].Value.ToString();
}
private string GetSeccodeHash(string html)
{
if (html.Contains("seccode"))
{
//\"seccode_(?'hash'.*?)\"
Match match = new Regex("\"seccode_(?'hash'.*?)\"", RegexOptions.None).Match(html);
return match.Groups["hash"].Value.ToString();
}
else
{
return null;
}
}
private string GetFormhash(string html)
{
Match match_FormHash = new Regex("<input type=\"hidden\" name=\"formhash\" value=\"(?<key>.*?)\" />", RegexOptions.None).Match(html);
return match_FormHash.Groups["key"].Value.ToString();
}
拿到secondhash后直接去请求获得验证码图片。
var url = $"misc.php?mod=seccode&action=update&idhash={SeccodeHash}&inajax=1&ajaxtarget=seccode_{SeccodeHash}"
这里又对referer进行了验证,验证未通过返回Access denied
拿到验证码图片后就简单了,公司论坛的图形验证码很简单基本没有什么干扰直接调用一个三方的识别API就搞定了。
最后提交的时候要把Loginhash带进去
var url = $"member.php?mod=logging&action=login&loginsubmit=yes&handlekey=login&loginhash={loginhash}&inajax=1"
验证码的结果和之前拿到的hash验证值放到form里面。
var params = "formhash={formhash}&referer=http%3A%2F%2Fwww.abc.com%2Fbbs%2Fforum.php&auth={auth}&seccodehash={seccodehash}&seccodemodid=member%3A%3Alogging&seccodeverify={verifycode}&loginsubmit=true"
这里面只有一个坑就是因为ID实名,编码格式是GB2132而非UTF8。
btw如果账号启用了安全提问验证登录,需要在form里面把问题编号和答案一起post过去。
登录成功以后拿到Cookie就可以根据tid在某些板块随机阅读帖子,发布新帖子或者回复内容以便完成考核任务自动化。。。
如果回帖的页面中包含了hidden seccode_ 就意味着回复内容需要填写验证码。
URL中包含了fid&tid
var url =$"forum.php?mod=post&action=reply&fid={fid}&tid={tid}&extra=&replysubmit=yes&infloat=yes&handlekey=fastpost&inajax=1"
Form中除去了日常的seccodehash和seccodeverify以及formhash就多了一个
seccodemodid
这个值一般是固定的在html用正则抓出去即可。
组合完成后直接post提交即可。
如果返回的html中正则匹配到了
succeedhandle_fastpost
代表服务器已经完成执行动作succeed
基本上没有什么困难点。只要细心观察留意与服务器的正常交互报文,用代码实现模拟下来没什么问题。
因为是4年前的代码了。所以没有贴图内容辅以佐证,只能在github上看着源代码回想简单讲一下。
传送门:github