using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Security.Cryptography; using System.Text; using System.Web; using DBHelper; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; using System.Configuration; using System.Web.Script.Serialization; namespace VECV_WebApi.Common { public class FirebaseNotificationSender { private static string serviceAccountPath = (ConfigurationManager.AppSettings["FCMJson"]); private static string firebaseProjectId = (ConfigurationManager.AppSettings["ProjectId"]); //private static string fcmUrl = $"https://fcm.googleapis.com/v1/projects/" + firebaseProjectId + "/messages:send"; private string fcmUrl; public FirebaseNotificationSender() { fcmUrl = $"https://fcm.googleapis.com/v1/projects/{firebaseProjectId}/messages:send"; } public string GetAccessTokenValue() { // var jwtGenerator = new GetAccessToken(); return GetAccessToken(); } public void SendNotification(string accessToken, string deviceToken, string title, string body) { var payload = new { message = new { token = deviceToken, notification = new { title = title, body = body } } }; string jsonPayload = JsonConvert.SerializeObject(payload); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fcmUrl); request.Method = "POST"; request.ContentType = "application/json"; request.Headers.Add("Authorization", "Bearer " + accessToken); using (StreamWriter writer = new StreamWriter(request.GetRequestStream())) { writer.Write(jsonPayload); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using (StreamReader reader = new StreamReader(response.GetResponseStream())) { string responseContent = reader.ReadToEnd(); Console.WriteLine("FCM Response: " + responseContent); } } private static string GetAccessToken() { string json = File.ReadAllText(serviceAccountPath); var keyData = new JavaScriptSerializer().Deserialize>(json); string clientEmail = keyData["client_email"].ToString(); string privateKey = keyData["private_key"].ToString(); string tokenUri = "https://oauth2.googleapis.com/token"; // Create JWT Header & Payload var now = DateTime.UtcNow; var payload = new Dictionary { { "iss", clientEmail }, { "scope", "https://www.googleapis.com/auth/firebase.messaging" }, { "aud", tokenUri }, { "iat", (int)(now - new DateTime(1970, 1, 1)).TotalSeconds }, { "exp", (int)(now.AddMinutes(60) - new DateTime(1970, 1, 1)).TotalSeconds } }; string jwt = CreateJwt(privateKey, payload); // Exchange JWT for OAuth Token using (var webClient = new WebClient()) { var requestParams = new Dictionary { { "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" }, { "assertion", jwt } }; string postData = new JavaScriptSerializer().Serialize(requestParams); webClient.Headers[HttpRequestHeader.ContentType] = "application/json"; string response = webClient.UploadString(tokenUri, postData); var responseObj = new JavaScriptSerializer().Deserialize>(response); return responseObj["access_token"].ToString(); } } private static string CreateJwt(string privateKey, Dictionary payload) { var rsaParams = GetRsaParameters(privateKey); var rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(rsaParams); var header = new { alg = "RS256", typ = "JWT" }; string encodedHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header))); string encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload))); string unsignedToken = $"{encodedHeader}.{encodedPayload}"; byte[] signature = rsa.SignData(Encoding.UTF8.GetBytes(unsignedToken), CryptoConfig.MapNameToOID("SHA256")); return $"{unsignedToken}.{Convert.ToBase64String(signature)}"; } private static RSAParameters GetRsaParameters(string privateKey) { var pemReader = new PemReader(new StringReader(privateKey)); var keyObject = pemReader.ReadObject(); // Handle the case where the private key is directly a RsaPrivateCrtKeyParameters if (keyObject is RsaPrivateCrtKeyParameters privateRsaParams) { return DotNetUtilities.ToRSAParameters(privateRsaParams); } // Handle AsymmetricCipherKeyPair (private and public key) if (keyObject is AsymmetricCipherKeyPair keyPair) { privateRsaParams = (RsaPrivateCrtKeyParameters)keyPair.Private; return DotNetUtilities.ToRSAParameters(privateRsaParams); } throw new InvalidOperationException("Unsupported private key format."); } } } /*static string jsonFilePath = @"path-to-your-service-account.json"; // Path to JSON file string accessToken = GetAccessTokenFromJsonFile(jsonFilePath); static string GetAccessTokenFromJsonFile(string jsonFilePath) { // Read JSON file string json = File.ReadAllText(jsonFilePath); var serviceAccountData = JsonConvert.DeserializeObject(json); if (serviceAccountData == null) { throw new Exception("Invalid service account JSON file."); } // Generate JWT string jwtToken = GenerateJwt(serviceAccountData); // Request access token string token = RequestAccessToken(jwtToken); return token; } static string RequestAccessToken(string jwtToken) { string tokenUrl = "https://oauth2.googleapis.com/token"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(tokenUrl); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; string postData = $"grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={jwtToken}"; byte[] byteArray = Encoding.UTF8.GetBytes(postData); request.ContentLength = byteArray.Length; using (Stream dataStream = request.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); } try { using (WebResponse response = request.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream())) { string responseString = reader.ReadToEnd(); var jsonResponse = JsonConvert.DeserializeObject(responseString); return jsonResponse.access_token; } } } catch (WebException ex) { using (var errorResponse = ex.Response) using (var reader = new StreamReader(errorResponse.GetResponseStream())) { string errorText = reader.ReadToEnd(); Console.WriteLine($"Error: {errorText}"); } return null; } } static string GenerateJwt(ServiceAccount serviceAccount) { long iat = GetUnixTimestamp(); long exp = iat + 3600; var header = new { alg = "RS256", typ = "JWT" }; var payload = new Dictionary { { "iss", serviceAccount.client_email }, { "sub", serviceAccount.client_email }, { "aud", "https://oauth2.googleapis.com/token" }, { "iat", iat }, { "exp", exp }, { "scope", "https://www.googleapis.com/auth/firebase.messaging" } }; string headerBase64 = Base64UrlEncode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header))); string payloadBase64 = Base64UrlEncode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload))); string unsignedToken = $"{headerBase64}.{payloadBase64}"; string signedJwt = SignJwt(unsignedToken, serviceAccount.private_key); return $"{unsignedToken}.{signedJwt}"; } public static long GetUnixTimestamp() { DateTimeOffset dateTimeOffset = DateTimeOffset.UtcNow; DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); TimeSpan elapsedTime = dateTimeOffset.UtcDateTime - epoch; return (long)elapsedTime.TotalSeconds; } static string SignJwt(string unsignedJwt, string privateKey) { byte[] privateKeyBytes = Convert.FromBase64String( privateKey .Replace("-----BEGIN PRIVATE KEY-----", "") .Replace("-----END PRIVATE KEY-----", "") .Replace("\n", "") ); using (RSACryptoServiceProvider rsa = ImportPrivateKey(privateKey)) { byte[] hash = HashData(unsignedJwt); byte[] signature = rsa.SignHash(hash, CryptoConfig.MapNameToOID("SHA256")); return Base64UrlEncode(signature); } } //static RSACryptoServiceProvider DecodePrivateKey(byte[] privateKeyBytes) //{ // var rsa = new RSACryptoServiceProvider(); // rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _); // If fails, try importing with OpenSSL-converted private key. // return rsa; //} public static RSACryptoServiceProvider ImportPrivateKey(string pem) { PemReader pr = new PemReader(new StringReader(pem)); AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject(); RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private); RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams); csp.ImportParameters(rsaParams); return csp; } static string Base64UrlEncode(byte[] input) { return Convert.ToBase64String(input) .TrimEnd('=') .Replace('+', '-') .Replace('/', '_'); } static byte[] HashData(string data) { using (SHA256 sha256 = SHA256.Create()) { return sha256.ComputeHash(Encoding.UTF8.GetBytes(data)); } } class ServiceAccount { public string type { get; set; } public string project_id { get; set; } public string private_key_id { get; set; } public string private_key { get; set; } public string client_email { get; set; } public string client_id { get; set; } public string auth_uri { get; set; } public string token_uri { get; set; } public string auth_provider_x509_cert_url { get; set; } public string client_x509_cert_url { get; set; } } } } */