From d33a77c80d63abf68002bc1f07d6183fcfb14c77 Mon Sep 17 00:00:00 2001 From: suyog phansekar Date: Mon, 10 May 2021 18:33:35 +0530 Subject: [PATCH 1/3] OTP Validation Code merge --- CoWin.Core/Auth/Captcha.cs | 4 +- CoWin.Core/Auth/OTPAuthenticator.cs | 109 ++++++++++++++++++ CoWin.Core/Models/CovidVaccinationCenter.cs | 25 +++- .../Models/CovidVaccinationCenterFinder.cs | 8 +- CoWin.Core/Models/OTPModel.cs | 25 ++++ CoWin.Core/Program.cs | 4 +- CoWin.Core/Providers/APIFacade.cs | 3 +- CoWin.Core/appsettings.json | 34 +++--- 8 files changed, 189 insertions(+), 23 deletions(-) create mode 100644 CoWin.Core/Auth/OTPAuthenticator.cs create mode 100644 CoWin.Core/Models/OTPModel.cs diff --git a/CoWin.Core/Auth/Captcha.cs b/CoWin.Core/Auth/Captcha.cs index bc5d180..1e32189 100644 --- a/CoWin.Core/Auth/Captcha.cs +++ b/CoWin.Core/Auth/Captcha.cs @@ -15,9 +15,11 @@ namespace CoWin.Auth public class Captcha { private readonly IConfiguration _configuration; - public Captcha(IConfiguration configuration) + private string _bearerToken; + public Captcha(IConfiguration configuration, string bearerToken) { _configuration = configuration; + _bearerToken = bearerToken; } public string GetCurrentCaptchaDetails() { diff --git a/CoWin.Core/Auth/OTPAuthenticator.cs b/CoWin.Core/Auth/OTPAuthenticator.cs new file mode 100644 index 0000000..07a1f18 --- /dev/null +++ b/CoWin.Core/Auth/OTPAuthenticator.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CoWiN.Models; +using Microsoft.Extensions.Configuration; +using System.IO; +using System.Threading; +using Newtonsoft.Json; +using CoWin.Models; +using RestSharp; +using CoWin.Providers; +using System.Net; +using System.Security.Cryptography; + +namespace CoWin.Auth +{ + class OTPAuthenticator + { + private IConfiguration _configuration; + public static string BEARER_TOKEN; + public OTPAuthenticator(IConfiguration configuration) + { + _configuration = configuration; + } + + public void ValidateUser() + { + string endpoint = ""; + + if (Convert.ToBoolean(_configuration["CoWinAPI:Auth:IsToBeUsed"])) + { + endpoint = _configuration["CoWinAPI:Auth:OTPGeneratorUrl"]; + } + string requestBody = JsonConvert.SerializeObject(new OtpModel + { + Mobile = _configuration["CoWinAPI:Auth:Mobile"], + Secret = _configuration["CoWinAPI:Auth:Secret"] + }); + var response = GenerateOTP(endpoint, requestBody); + string otp = ""; + if (response.StatusCode == HttpStatusCode.OK) + { + Console.WriteLine($"[INFO] OTP Generated for Mobile No: {_configuration["CoWinAPI:Auth:Mobile"]} at {DateTime.Now}"); + var txnID = JsonConvert.DeserializeObject(response.Content); + endpoint = _configuration["CoWinAPI:Auth:OTPValidatorUrl"]; + otp = ComputeSha256Hash(ReadUserInput("Please Enter OTP: ")); + requestBody = JsonConvert.SerializeObject(new OtpModel + { + TransactionId = txnID.TransactionId, + Otp = otp + }); + response = ValidateOTP(endpoint, requestBody); + if (response.StatusCode == HttpStatusCode.OK) + { + Console.WriteLine($"[INFO] User Validated with Mobile No {_configuration["CoWinAPI:Auth:Mobile"]}"); + BEARER_TOKEN = JsonConvert.DeserializeObject(response.Content).BearerToken; + } + else + { + DisplayErrorMessage(response); + } + } + else + { + DisplayErrorMessage(response); + } + + } + + private IRestResponse GenerateOTP(string endpoint, string requestBody) + { + IRestResponse response = new APIFacade(_configuration).Post(endpoint, requestBody); + return response; + } + + private IRestResponse ValidateOTP(string endpoint, string requestBody) + { + IRestResponse response = new APIFacade(_configuration).Post(endpoint, requestBody); + return response; + } + void DisplayErrorMessage(IRestResponse response) + { + if (response.StatusCode != HttpStatusCode.OK) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"[ERROR] OTP Error - ResponseCode: {response.StatusDescription} ResponseData: {response.Content}"); + } + } + private string ReadUserInput(string message) + { + Console.WriteLine(message); + string userInput = Console.ReadLine(); + return userInput; + } + static string ComputeSha256Hash(string rawData) + { + using (SHA256 sha256Hash = SHA256.Create()) + { + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < bytes.Length; i++) + { + builder.Append(bytes[i].ToString("x2")); + } + return builder.ToString(); + } + } + } +} diff --git a/CoWin.Core/Models/CovidVaccinationCenter.cs b/CoWin.Core/Models/CovidVaccinationCenter.cs index 95fbc36..a6187af 100644 --- a/CoWin.Core/Models/CovidVaccinationCenter.cs +++ b/CoWin.Core/Models/CovidVaccinationCenter.cs @@ -13,7 +13,7 @@ namespace CoWiN.Models public class CovidVaccinationCenter { private readonly IConfiguration _configuration; - + private string _bearerToken; public CovidVaccinationCenter(IConfiguration configuration) { _configuration = configuration; @@ -27,6 +27,12 @@ public void GetSlotsByDistrictId(string districtId, string searchDate, string va var covidVaccinationCenters = JsonConvert.DeserializeObject(response.Content); GetAvailableSlots(covidVaccinationCenters); } + else if (response.StatusCode == HttpStatusCode.Unauthorized) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"[WARNING] Session Expired : Regenerating Auth Token"); + new OTPAuthenticator(_configuration).ValidateUser(); + } else { Console.ForegroundColor = ConsoleColor.Red; @@ -43,6 +49,12 @@ public void GetSlotsByPINCode(string pinCode, string searchDate, string vaccineT var covidVaccinationCenters = JsonConvert.DeserializeObject(response.Content); GetAvailableSlots(covidVaccinationCenters); } + else if (response.StatusCode == HttpStatusCode.Unauthorized) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"[WARNING] Session Expired : Regenerating Auth Token"); + new OTPAuthenticator(_configuration).ValidateUser(); + } else { Console.ForegroundColor = ConsoleColor.Red; @@ -107,7 +119,7 @@ private void GetAvailableSlots(CovidVaccinationCenters covidVaccinationCenters) Console.WriteLine($"Trying to Book Appointment for CVC: {cvc.Name} - PIN: {cvc.Pincode} - District: {cvc.DistrictName} - Date: {session.Date} - Slot: {slot}"); Console.ResetColor(); - captcha = new Captcha(_configuration).GetCurrentCaptchaDetails(); + captcha = new Captcha(_configuration, _bearerToken).GetCurrentCaptchaDetails(); var isBookingSuccessful = BookAvailableSlot(session.SessionId, slot, captcha); @@ -141,9 +153,6 @@ private static void DisplaySlotInfo(Center cvc, Session session) Console.WriteLine("AvailableCapacity: " + session.AvailableCapacity); Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("DateOfAvailability: " + session.Date); - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine("SessionId: " + session.SessionId); - Console.ResetColor(); Console.WriteLine("Slots Available: " + string.Join(", ", session.Slots)); Console.WriteLine("***************************************************************************************************************\n"); } @@ -181,6 +190,12 @@ private bool BookAvailableSlot(string sessionId, string slot, string captcha) Console.ResetColor(); isBookingSuccessful = true; } + else if (response.StatusCode == HttpStatusCode.Unauthorized) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"[WARNING] Session Expired : Regenerating Auth Token"); + new OTPAuthenticator(_configuration).ValidateUser(); + } else { Console.ForegroundColor = ConsoleColor.Red; diff --git a/CoWin.Core/Models/CovidVaccinationCenterFinder.cs b/CoWin.Core/Models/CovidVaccinationCenterFinder.cs index fd6dd73..6d61ffd 100644 --- a/CoWin.Core/Models/CovidVaccinationCenterFinder.cs +++ b/CoWin.Core/Models/CovidVaccinationCenterFinder.cs @@ -15,6 +15,7 @@ public class CovidVaccinationCenterFinder private List pinCodesToSearch = new List(); private string searchDate; private string vaccineType; + public CovidVaccinationCenterFinder() { _configuration = new ConfigurationBuilder() @@ -22,13 +23,18 @@ public CovidVaccinationCenterFinder() .AddJsonFile("appsettings.json", false, true) .Build(); } - public void FindSlot() { + AuthenticateUser(); ConfigureSearchCriteria(); SearchForAvailableSlots(); } + private void AuthenticateUser() + { + new OTPAuthenticator(_configuration).ValidateUser(); + } + private void SearchForAvailableSlots() { for (int i = 1; i < Convert.ToInt32(_configuration["CoWinAPI:TotalIterations"]); i++) diff --git a/CoWin.Core/Models/OTPModel.cs b/CoWin.Core/Models/OTPModel.cs new file mode 100644 index 0000000..5993c60 --- /dev/null +++ b/CoWin.Core/Models/OTPModel.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; + +namespace CoWin.Models +{ + public partial class OtpModel + { + [JsonProperty("secret")] + public string Secret { get; set; } + + [JsonProperty("mobile")] + public string Mobile { get; set; } + + [JsonProperty("txnId")] + public string TransactionId { get; set; } + + [JsonProperty("otp")] + public string Otp { get; set; } + + [JsonProperty("token")] + public string BearerToken { get; set; } + } +} \ No newline at end of file diff --git a/CoWin.Core/Program.cs b/CoWin.Core/Program.cs index 2c04c2c..1d8f7b1 100644 --- a/CoWin.Core/Program.cs +++ b/CoWin.Core/Program.cs @@ -1,4 +1,5 @@ -using CoWin.Models; +using CoWin.Auth; +using CoWin.Models; using System; namespace CoWin @@ -7,6 +8,7 @@ public class Program { public static void Main() { + new CovidVaccinationCenterFinder().FindSlot(); Console.WriteLine("Press Enter to Exit"); Console.ReadKey(); diff --git a/CoWin.Core/Providers/APIFacade.cs b/CoWin.Core/Providers/APIFacade.cs index da2bcad..a9e1fb6 100644 --- a/CoWin.Core/Providers/APIFacade.cs +++ b/CoWin.Core/Providers/APIFacade.cs @@ -2,6 +2,7 @@ using System; using Microsoft.Extensions.Configuration; using System.Net; +using CoWin.Auth; namespace CoWin.Providers { @@ -34,7 +35,7 @@ private void AddGenericHeaders(IRestRequest request) { request.AddHeader("Origin", _configuration["CoWinAPI:SelfRegistrationPortal"]); request.AddHeader("Referer", _configuration["CoWinAPI:SelfRegistrationPortal"]); - request.AddHeader("Authorization", $"Bearer {_configuration["CoWinAPI:ProtectedAPI:BearerToken"]}"); + request.AddHeader("Authorization", $"Bearer {OTPAuthenticator.BEARER_TOKEN}"); } } diff --git a/CoWin.Core/appsettings.json b/CoWin.Core/appsettings.json index bde103f..935d054 100644 --- a/CoWin.Core/appsettings.json +++ b/CoWin.Core/appsettings.json @@ -4,28 +4,34 @@ "FetchCalenderByDistrictUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/calendarByDistrict", "FetchCalenderByPINUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/calendarByPin" }, + "ProtectedAPI": { + "IsToBeUsed": true, + "FetchCalenderByDistrictUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/calendarByDistrict", + "FetchCalenderByPINUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/calendarByPin", + "ScheduleAppointmentUrl": "https://cdn-api.co-vin.in/api/v2/appointment/schedule", + "CaptchaGenerationUrl": "https://cdn-api.co-vin.in/api/v2/auth/getRecaptcha", + "BeneficiaryId": "21395953301115" + }, + "Auth": { + "IsToBeUsed": true, + "OTPGeneratorUrl": "https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP", + "OTPValidatorUrl": "https://cdn-api.co-vin.in/api/v2/auth/validateMobileOtp", + "Secret": "U2FsdGVkX18vDwDor+oOIG7vSUnINtlc/pxQcNiBulCm8LT5Sza+aIISKLqImbpMnRYgsN2QACPhggLWgZEpQg==", + "Mobile": "8805892611" + }, "MinAgeLimit": 18, - "MaxAgeLimit": 47, + "MaxAgeLimit": 45, "MinimumVaccineAvailability": 1, "VaccineType": "COVISHIELD", "DoseType": 1, "VaccineFeeType": "Free", "SleepIntervalInMilliseconds": 2000, - "TotalIterations": 2, + "TotalIterations": 10000, "SpoofedUserAgentToBypassWAF": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36", "SelfRegistrationPortal": "https://selfregistration.cowin.gov.in", "IsSearchToBeDoneByDistrict": false, "IsSearchToBeDoneByPINCode": true, - "DateToSearch": "10-05-2021", // DD-MM-YYYY Format, Blank implies current date - "ProtectedAPI": { - "IsToBeUsed": true, - "FetchCalenderByDistrictUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/calendarByDistrict", - "FetchCalenderByPINUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/calendarByPin", - "ScheduleAppointmentUrl": "https://cdn-api.co-vin.in/api/v2/appointment/schedule", - "CaptchaGenerationUrl": "https://cdn-api.co-vin.in/api/v2/auth/getRecaptcha", - "BeneficiaryId": "", - "BearerToken": "" - } + "DateToSearch": "10-05-2021" // DD-MM-YYYY Format, Blank implies current date }, "Districts": { // "DistrictName": DistrictCode @@ -36,8 +42,8 @@ "PINCodes": { // "PlaceName": PinCode //"Nerul": 400706, - "Nagpur": 440002 - //"Bhandara": 441904 + //"Nagpur": 440002 + "Bhandara": 441904 //, "Andheri": 400058 //, "BKC": 400051 //, "Ghatkopar": 400077 From 89694d6602fb6868b2b8ef5bedeef7e07759f180 Mon Sep 17 00:00:00 2001 From: suyog phansekar Date: Mon, 10 May 2021 18:53:13 +0530 Subject: [PATCH 2/3] Adding files after refactoring --- .gitignore | 9 +++++++++ CoWin.Core/Auth/Captcha.cs | 4 +--- CoWin.Core/Models/CovidVaccinationCenter.cs | 3 +-- CoWin.Core/Program.cs | 3 +-- CoWin.Core/appsettings.json | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9b3e4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/CoWin.Core/bin/Debug/netcoreapp3.1 +/CoWin.Core/obj +/CoWin.UI/obj +/.vs +/CoWin.UI/bin/Debug/netcoreapp3.1 diff --git a/CoWin.Core/Auth/Captcha.cs b/CoWin.Core/Auth/Captcha.cs index 1e32189..bc5d180 100644 --- a/CoWin.Core/Auth/Captcha.cs +++ b/CoWin.Core/Auth/Captcha.cs @@ -15,11 +15,9 @@ namespace CoWin.Auth public class Captcha { private readonly IConfiguration _configuration; - private string _bearerToken; - public Captcha(IConfiguration configuration, string bearerToken) + public Captcha(IConfiguration configuration) { _configuration = configuration; - _bearerToken = bearerToken; } public string GetCurrentCaptchaDetails() { diff --git a/CoWin.Core/Models/CovidVaccinationCenter.cs b/CoWin.Core/Models/CovidVaccinationCenter.cs index a6187af..9263cd0 100644 --- a/CoWin.Core/Models/CovidVaccinationCenter.cs +++ b/CoWin.Core/Models/CovidVaccinationCenter.cs @@ -13,7 +13,6 @@ namespace CoWiN.Models public class CovidVaccinationCenter { private readonly IConfiguration _configuration; - private string _bearerToken; public CovidVaccinationCenter(IConfiguration configuration) { _configuration = configuration; @@ -119,7 +118,7 @@ private void GetAvailableSlots(CovidVaccinationCenters covidVaccinationCenters) Console.WriteLine($"Trying to Book Appointment for CVC: {cvc.Name} - PIN: {cvc.Pincode} - District: {cvc.DistrictName} - Date: {session.Date} - Slot: {slot}"); Console.ResetColor(); - captcha = new Captcha(_configuration, _bearerToken).GetCurrentCaptchaDetails(); + captcha = new Captcha(_configuration).GetCurrentCaptchaDetails(); var isBookingSuccessful = BookAvailableSlot(session.SessionId, slot, captcha); diff --git a/CoWin.Core/Program.cs b/CoWin.Core/Program.cs index 1d8f7b1..e23a2c2 100644 --- a/CoWin.Core/Program.cs +++ b/CoWin.Core/Program.cs @@ -1,5 +1,4 @@ -using CoWin.Auth; -using CoWin.Models; +using CoWin.Models; using System; namespace CoWin diff --git a/CoWin.Core/appsettings.json b/CoWin.Core/appsettings.json index 935d054..649049a 100644 --- a/CoWin.Core/appsettings.json +++ b/CoWin.Core/appsettings.json @@ -10,14 +10,14 @@ "FetchCalenderByPINUrl": "https://cdn-api.co-vin.in/api/v2/appointment/sessions/calendarByPin", "ScheduleAppointmentUrl": "https://cdn-api.co-vin.in/api/v2/appointment/schedule", "CaptchaGenerationUrl": "https://cdn-api.co-vin.in/api/v2/auth/getRecaptcha", - "BeneficiaryId": "21395953301115" + "BeneficiaryId": "" }, "Auth": { "IsToBeUsed": true, "OTPGeneratorUrl": "https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP", "OTPValidatorUrl": "https://cdn-api.co-vin.in/api/v2/auth/validateMobileOtp", "Secret": "U2FsdGVkX18vDwDor+oOIG7vSUnINtlc/pxQcNiBulCm8LT5Sza+aIISKLqImbpMnRYgsN2QACPhggLWgZEpQg==", - "Mobile": "8805892611" + "Mobile": "" }, "MinAgeLimit": 18, "MaxAgeLimit": 45, From c412448f12bb652c5a8d1680a7c38cb8c724fa14 Mon Sep 17 00:00:00 2001 From: Saurav Saha Date: Mon, 10 May 2021 18:56:48 +0530 Subject: [PATCH 3/3] Delete .gitignore --- .gitignore | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a9b3e4d..0000000 --- a/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -################################################################################ -# This .gitignore file was automatically created by Microsoft(R) Visual Studio. -################################################################################ - -/CoWin.Core/bin/Debug/netcoreapp3.1 -/CoWin.Core/obj -/CoWin.UI/obj -/.vs -/CoWin.UI/bin/Debug/netcoreapp3.1