mirror of
https://github.com/nheiniger/SnaffPoint
synced 2026-06-08 16:23:31 +00:00
327 lines
12 KiB
C#
327 lines
12 KiB
C#
using SearchQueryTool.Helpers;
|
|
using SearchQueryTool.Model;
|
|
using System;
|
|
using System.Collections.Specialized;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
|
|
namespace SnaffPoint
|
|
{
|
|
class Program
|
|
{
|
|
private static string PresetPath = "./presets";
|
|
private static int MaxRows = 50;
|
|
private static string SingleQueryText = null;
|
|
private static SearchPresetList _SearchPresets;
|
|
private static string BearerToken = null;
|
|
private static string SPUrl = null;
|
|
private static bool isFQL = false;
|
|
private static string RefinementFilters = null;
|
|
|
|
private static void LoadSearchPresetsFromFolder(string presetFolderPath)
|
|
{
|
|
try
|
|
{
|
|
_SearchPresets = new SearchPresetList(presetFolderPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Failed to read search presets. Error: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private static SearchQueryResult StartSearchQueryRequest(SearchQueryRequest request)
|
|
{
|
|
SearchQueryResult searchResults = null;
|
|
try
|
|
{
|
|
HttpRequestResponsePair requestResponsePair = HttpRequestRunner.RunWebRequest(request);
|
|
if (requestResponsePair != null)
|
|
{
|
|
HttpWebResponse response = requestResponsePair.Item2;
|
|
if (null != response)
|
|
{
|
|
if (!response.StatusCode.Equals(HttpStatusCode.OK))
|
|
{
|
|
string status = String.Format("HTTP {0} {1}", (int)response.StatusCode, response.StatusDescription);
|
|
Console.WriteLine("Request returned with following status: " + status);
|
|
}
|
|
}
|
|
}
|
|
searchResults = GetResultItem(requestResponsePair);
|
|
|
|
// success, return the results
|
|
return searchResults;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Request failed with exception: " + ex.Message);
|
|
}
|
|
return searchResults;
|
|
}
|
|
|
|
private static SearchQueryResult GetResultItem(HttpRequestResponsePair requestResponsePair)
|
|
{
|
|
SearchQueryResult searchResults;
|
|
var request = requestResponsePair.Item1;
|
|
|
|
using (var response = requestResponsePair.Item2)
|
|
{
|
|
using (var reader = new StreamReader(response.GetResponseStream()))
|
|
{
|
|
var content = reader.ReadToEnd();
|
|
NameValueCollection requestHeaders = new NameValueCollection();
|
|
foreach (var header in request.Headers.AllKeys)
|
|
{
|
|
requestHeaders.Add(header, request.Headers[header]);
|
|
}
|
|
|
|
NameValueCollection responseHeaders = new NameValueCollection();
|
|
foreach (var header in response.Headers.AllKeys)
|
|
{
|
|
responseHeaders.Add(header, response.Headers[header]);
|
|
}
|
|
|
|
string requestContent = "";
|
|
if (request.Method == "POST")
|
|
{
|
|
requestContent = requestResponsePair.Item3;
|
|
}
|
|
|
|
searchResults = new SearchQueryResult
|
|
{
|
|
RequestUri = request.RequestUri,
|
|
RequestMethod = request.Method,
|
|
RequestContent = requestContent,
|
|
ContentType = response.ContentType,
|
|
ResponseContent = content,
|
|
RequestHeaders = requestHeaders,
|
|
ResponseHeaders = responseHeaders,
|
|
StatusCode = response.StatusCode,
|
|
StatusDescription = response.StatusDescription,
|
|
HttpProtocolVersion = response.ProtocolVersion.ToString()
|
|
};
|
|
searchResults.Process();
|
|
}
|
|
}
|
|
return searchResults;
|
|
}
|
|
|
|
static void QueryAllPresets()
|
|
{
|
|
LoadSearchPresetsFromFolder(PresetPath);
|
|
|
|
if (_SearchPresets.Presets.Count > 0)
|
|
{
|
|
foreach (var preset in _SearchPresets.Presets)
|
|
{
|
|
Console.WriteLine("\n" + preset.Name + "\n" + new String('=', preset.Name.Length) + "\n");
|
|
preset.Request.Token = BearerToken;
|
|
preset.Request.SharePointSiteUrl = SPUrl;
|
|
preset.Request.RowLimit = MaxRows;
|
|
preset.Request.AcceptType = AcceptType.Json;
|
|
preset.Request.AuthenticationType = AuthenticationType.SPOManagement; // force to JWT auth method
|
|
// Console.WriteLine("DEBUG - Request: " + preset.Request.ToString());
|
|
SearchQueryResult results = StartSearchQueryRequest(preset.Request);
|
|
DisplayResults(results);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("No presets were found in " + PresetPath);
|
|
}
|
|
}
|
|
|
|
private static void DisplayResults(SearchQueryResult results)
|
|
{
|
|
if (results != null)
|
|
{
|
|
if (results.PrimaryQueryResult != null)
|
|
{
|
|
Console.WriteLine("Found " + results.PrimaryQueryResult.TotalRows + " results");
|
|
if (results.PrimaryQueryResult.TotalRows > MaxRows)
|
|
{
|
|
Console.WriteLine("Only showing " + MaxRows + " results, though!");
|
|
}
|
|
if (results.PrimaryQueryResult.TotalRows > 0)
|
|
{
|
|
foreach (ResultItem item in results.PrimaryQueryResult.RelevantResults)
|
|
{
|
|
Console.WriteLine("---");
|
|
Console.WriteLine(item.Title);
|
|
Console.WriteLine(item.Path);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Found no results... maybe the request failed?");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Result are null ! What happened there?");
|
|
}
|
|
}
|
|
|
|
private static void DoSingleQuery()
|
|
{
|
|
// preparing the request for you
|
|
SearchQueryRequest request = new SearchQueryRequest
|
|
{
|
|
SharePointSiteUrl = SPUrl,
|
|
AcceptType = AcceptType.Json,
|
|
Token = BearerToken,
|
|
AuthenticationType = AuthenticationType.SPOManagement,
|
|
QueryText = SingleQueryText,
|
|
HttpMethodType = HttpMethodType.Get,
|
|
EnableFql = isFQL,
|
|
RowLimit = MaxRows
|
|
};
|
|
if (RefinementFilters != null)
|
|
{
|
|
request.RefinementFilters = RefinementFilters;
|
|
}
|
|
// DO IT, DO IT, DO IT !
|
|
SearchQueryResult results = StartSearchQueryRequest(request);
|
|
DisplayResults(results);
|
|
}
|
|
|
|
static void PrintHelp()
|
|
{
|
|
Console.WriteLine(
|
|
@"
|
|
.dBBBBP dBBBBb dBBBBBb dBBBBP dBBBBP dBBBBBb dBBBBP dBP dBBBBb dBBBBBBP
|
|
BP dBP BB dB' dBP.BP dBP
|
|
`BBBBb dBP dBP dBP BB dBBBP dBBBP dBBBP' dBP.BP dBP dBP dBP dBP
|
|
dBP dBP dBP dBP BB dBP dBP dBP dBP.BP dBP dBP dBP dBP
|
|
dBBBBP' dBP dBP dBBBBBBB dBP dBP dBP dBBBBP dBP dBP dBP dBP
|
|
|
|
https://github.com/nheiniger/snaffpoint
|
|
|
|
SnaffPoint, candy finder for SharePoint
|
|
|
|
Usage: SnaffPoint.exe -u URL -t JWT [OPTIONS]
|
|
|
|
-h, --help This is me :)
|
|
|
|
Mandatory:
|
|
-u, --url SharePoint online URL where you want to search
|
|
-t, --token Bearer token that grants access to said SharePoint
|
|
|
|
Common options:
|
|
-m, --max-rows Max. number of rows to return per search query (default is 50)
|
|
|
|
Presets mode (default):
|
|
-p, --preset Path to a folder containing XML search presets (default is ./presets)
|
|
|
|
Single query mode:
|
|
-q, --query Query search string
|
|
-l, --fql Enables FQL (default is KQL)
|
|
-r, --refinement-filter Adds a refinement filter");
|
|
}
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
foreach (var entry in args.Select((value, index) => new { index, value }))
|
|
{
|
|
switch (entry.value)
|
|
{
|
|
// do you want FQL powaa?
|
|
case "-l":
|
|
case "--fql":
|
|
isFQL = true;
|
|
break;
|
|
// no need for hundreds of results
|
|
case "-m":
|
|
case "--max-rows":
|
|
if (args[entry.index + 1].StartsWith("-"))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
if (! int.TryParse(args[entry.index + 1], out MaxRows))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
break;
|
|
// preset path, load presets
|
|
case "-p":
|
|
case "--preset":
|
|
if (args[entry.index + 1].StartsWith("-"))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
PresetPath = args[entry.index + 1];
|
|
break;
|
|
// single query
|
|
case "-q":
|
|
case "--query":
|
|
if (args[entry.index + 1].StartsWith("-"))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
SingleQueryText = args[entry.index + 1];
|
|
break;
|
|
// fine control is good :)
|
|
case "-r":
|
|
case "--refinement-filter":
|
|
if (args[entry.index + 1].StartsWith("-"))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
RefinementFilters = args[entry.index + 1];
|
|
break;
|
|
// Bearer token (JWT)
|
|
case "-t":
|
|
case "--token":
|
|
if (args[entry.index + 1].StartsWith("-"))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
BearerToken = "Bearer " + args[entry.index + 1];
|
|
break;
|
|
// SharePoint online URL
|
|
case "-u":
|
|
case "--url":
|
|
if (args[entry.index + 1].StartsWith("-"))
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
SPUrl = args[entry.index + 1];
|
|
break;
|
|
// send help
|
|
case "-h":
|
|
case "--help":
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// did you read the doc?
|
|
if (SPUrl == null || BearerToken == null)
|
|
{
|
|
PrintHelp();
|
|
return;
|
|
}
|
|
|
|
// if you specify a query I assume you want an answer, otherwise I have some defaults
|
|
if (SingleQueryText != null)
|
|
{
|
|
DoSingleQuery();
|
|
}
|
|
else
|
|
{
|
|
QueryAllPresets();
|
|
}
|
|
}
|
|
}
|
|
}
|