Files
cdrtool/Gmail.cs
Doug Macintosh 336b0dbb7e first real commit
2026-03-08 17:05:59 -04:00

160 lines
6.1 KiB
C#

using System;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Text.RegularExpressions;
using System.Runtime.Remoting.Messaging;
namespace cdrtool
{
class Gmail
{
static string[] Scopes = { GmailService.Scope.GmailReadonly };
static string ApplicationName = "Gmail API .NET Quickstart";
public static async Task<string> GetMail()
{
UserCredential credential;
string mfa_code = "";
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = "token.json";
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.FromStream(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true));
//Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define the timestamp after which we want to find emails (in Unix time format).
DateTime afterTimestamp = new DateTime(2024, 01, 01); // Use this when you cannot generate a new mfs email to test with
afterTimestamp = DateTime.Now; // We do this to ensure we get the latest auth email, usually 2-3 seconds after this fires
long afterUnixTimestamp = ((DateTimeOffset)afterTimestamp).ToUnixTimeSeconds();
Logger.Log(1,"Awaiting MFA email (max {0}s)", cdrtool.mfa_delay);
bool repeat = false;
int count = cdrtool.mfa_delay;
do
{
// Fetch emails received after the given timestamp
var request = service.Users.Messages.List("me");
request.Q = $"after:{afterUnixTimestamp} from:\"Rogers SIP Portal\" "; //refinement added Sep16 2024
ListMessagesResponse response = await request.ExecuteAsync();
var messages = response.Messages?.OrderByDescending(m => m.InternalDate).ToList();
repeat = (messages == null);
//Console.WriteLine("Messages count: {0}", (messages != null) ? messages.Count : 0 );
if (messages != null && messages.Any())
{
//Console.WriteLine("Messages count: {0}",messages.Count);
var mostRecentMessage = messages.First();
Message message = await service.Users.Messages.Get("me", mostRecentMessage.Id).ExecuteAsync();
try
{
Regex word = new Regex(@".*Your Portal.+([0-9]{6})"); // MFA looking for 6 digit code //refinement added Sep16 2024
Match m = word.Match(message.Snippet); // .Snippet easily grabs enough plain text to find the MFA code
if (m.Success)
{
Group g = m.Groups[1];
//Capture c = g.Captures[0];
Logger.Log(6, "Regex Match {0} / Group Count {1} / Captures Count {2} / result={3}", m.Success, m.Groups.Count, m.Captures.Count, g.Value);
int code = Convert.ToInt32(g.Value);
if ((code >= 0) && (code <= 999999))
Logger.Log(5, "Code found successfully {0}", code);
mfa_code = g.Value;
repeat = false;
}
else
{
Logger.Log(1, "No code found in email.");
}
}
catch (Exception e)
{
Logger.Log(0, "Error parsing Gmail. {0}", e.Message);
}
}
else
{
int incr = 1;
if (count <= (cdrtool.mfa_delay - 5) ) incr = 5;
count-= incr;
System.Threading.Thread.Sleep(1000 * incr);
Logger.Log(1, "No message found for {0}s", cdrtool.mfa_delay - count);
}
}
while (repeat && (count > 0) );
Logger.Log(0, "Emailed MFA Code : {0}", mfa_code);
return mfa_code;
}
static string GetPlainTextFromMessageParts(IList<MessagePart> parts)
{
if (parts == null)
return string.Empty;
foreach (var part in parts)
{
//Console.WriteLine("email: type:{0}\nbody:\n{1}", part.MimeType, part.Body.Data);
if (part.MimeType == "text/plain" && part.Body != null && part.Body.Data != null)
{
return Base64UrlDecode(part.Body.Data);
}
else if (part.Parts != null)
{
string text = GetPlainTextFromMessageParts(part.Parts);
if (!string.IsNullOrEmpty(text))
return text;
}
}
return string.Empty;
}
static string Base64UrlDecode(string input)
{
string s = input.Replace('-', '+').Replace('_', '/');
switch (s.Length % 4)
{
case 2: s += "=="; break;
case 3: s += "="; break;
}
var bytes = Convert.FromBase64String(s);
return System.Text.Encoding.UTF8.GetString(bytes);
}
}
}