using Google.Apis.Auth.OAuth2; using Google.Cloud.Firestore; using Grpc.Auth; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Security.Claims; using System.Text; using System.Threading.Tasks; using Teso_API.Methods; using Teso_API.Methods.Controllers; using Teso_API.Models; namespace Teso_API.AuthControllers { [Route("api/[controller]")] [ApiController] public class GoogleAuthController : ControllerBase { public IConfiguration _configuration; private readonly TESOContext _context; private FirestoreDb db; readonly ITokenService tokenService; public GoogleAuthController(TESOContext context, IConfiguration config,ITokenService tokenService) { _context = context; _configuration = config; db = new FirestoreDbBuilder { ProjectId = ServerLocation.credentials.project_id, ChannelCredentials = GoogleCredential.FromJson(JsonConvert.SerializeObject(ServerLocation.credentials)).ToChannelCredentials(), }.Build(); this.tokenService = tokenService ?? throw new ArgumentNullException(nameof(tokenService)); } [HttpPost] public async Task> Post(GoogleUser user) { Models.TokenHandler tokenHandler = new Models.TokenHandler(); if (!UserAuthExists(user.UserGUID)) { //if (user.pictureUri != null) // user.pictureUri = await GetImageAsBase64Url(user.pictureUri); UserAuth auth = new UserAuth(); auth.UserGUID = user.UserGUID; auth.Status = "verified"; auth.AccountType = await _context.AccountTypes.AsQueryable().Where(u => u.TypeName.ToLower() == "google").Select(f => f.TypeCode).FirstOrDefaultAsync(); string[] splitted = user.Email.Split("@"[0]); auth.Username = splitted[0]; auth.DeviceToken = user.devicetoken; TesoUserDetail detail = new TesoUserDetail(); detail.UserGUID = user.UserGUID; detail.Username = splitted[0]; detail.ThumbnailDp = user.pictureUri; detail.Email = user.Email; detail.Gender = user.Gender; detail.Country = "+233"; detail.Firstname = user.Firstname; detail.Surname = user.Surname; if (TesoUserDetailExists(detail.Username)) { detail.Username = user.UserGUID; auth.Username = user.UserGUID; } Registrar registrar = new Registrar(); registrar.user = detail; registrar.authentication = auth; registrar.referral = user.referral; if (!EmailExists(user.Email)) { int statusCode = await RegisterUser(registrar); if (statusCode == 200) { return await Authenticate(auth); } else { return BadRequest(); } } else { return BadRequest(); } } else { UserAuth auth = new UserAuth(); auth.UserGUID = user.UserGUID; auth.Status = "verified"; auth.AccountType = await _context.AccountTypes.AsQueryable().Where(u => u.TypeName.ToLower() == "google").Select(f => f.TypeCode).FirstOrDefaultAsync(); string[] splitted = user.Email.Split("@"[0]); auth.DeviceToken = user.devicetoken; return await Authenticate(auth); } } public async Task RegisterUser(Registrar userAuth) { WriteBatch batch = db.StartBatch(); if (String.IsNullOrEmpty(userAuth.referral) || (!String.IsNullOrEmpty(userAuth.referral) && (_context.Referrals.AsQueryable().Where(r => r.Referrer == userAuth.referral && r.Datejoined.Value.Date == DateTime.Now.Date).Count()) >= 50)) { UserFinance finance = new UserFinance(); finance.Gold = 0; finance.Silver = 52; finance.UserGUID = userAuth.user.UserGUID; UserTransaction transaction = new UserTransaction(); transaction.RealCash = 0; transaction.CoinType = await _context.CoinTypes.AsQueryable().Where(c => c.TypeName.ToLower().Contains("silver")).Select(s => s.TypeCode).AsNoTracking().FirstOrDefaultAsync(); transaction.Comments = "Welcome bonus"; transaction.CoinAmount = 52; transaction.Timestamp = DateTime.Now; transaction.TransactionID = String.Format("{0:d9}", (DateTime.Now.Ticks / 10) % 10000000) + userAuth.user.UserGUID; transaction.UserGUID = userAuth.user.UserGUID; transaction.TransactionType = await _context.TransactionTypes.AsQueryable().Where(c => c.TypeName.ToLower().Contains("silver credit")).Select(c => c.TypeCode).AsNoTracking().FirstOrDefaultAsync(); _context.UserTransactions.Add(transaction); bool possible = await SilverBankOperations.WithdrawFromBank(52, _context); if (!possible) return 400; if (!String.IsNullOrEmpty(userAuth.referral)) { _context.Referrals.Add(new Referral { Datejoined = DateTime.Now, Referred = userAuth.user.UserGUID, Referrer = userAuth.referral, Rewarded = false, }); } DocumentReference docRef = db.Collection(ServerLocation.user_notifications).Document(userAuth.user.UserGUID).Collection(userAuth.user.UserGUID).Document(); Dictionary user = new Dictionary { { "notificationType", "welcome" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", "Welcome to Teso App, as your welcome package you have been gifted 52 Silvers Coins for free. You may use them to acquire discount and freebie coupons!!!" }, { "recipient", userAuth.user.UserGUID }, }; batch.Set(docRef, user); _context.UserFinances.Add(finance); } else { List finances = new List{ new UserFinance { Gold = 0, Silver = 52, UserGUID = userAuth.user.UserGUID, }, new UserFinance { Gold = 0, Silver = 10, UserGUID = userAuth.referral, }, }; List transactions = new List() { new UserTransaction { RealCash = 0, CoinType = await _context.CoinTypes.AsQueryable().Where(c => c.TypeName.ToLower().Contains("silver")).Select(s => s.TypeCode).AsNoTracking().FirstOrDefaultAsync(), Comments = "Welcome bonus", CoinAmount = 52, Timestamp = DateTime.Now, TransactionID = String.Format("{0:d9}", (DateTime.Now.Ticks / 10) % 10000000) + userAuth.user.UserGUID, UserGUID = userAuth.user.UserGUID, TransactionType = await _context.TransactionTypes.AsQueryable().Where(c => c.TypeName.ToLower().Contains("silver credit")).Select(c => c.TypeCode).AsNoTracking().FirstOrDefaultAsync(), }, new UserTransaction { RealCash = 0, CoinType = await _context.CoinTypes.AsQueryable().Where(c => c.TypeName.ToLower().Contains("silver")).Select(s => s.TypeCode).AsNoTracking().FirstOrDefaultAsync(), Comments = "Referral bonus", CoinAmount = 10, Timestamp = DateTime.Now, TransactionID = String.Format("{0:d9}", (DateTime.Now.Ticks / 10) % 10000000) + userAuth.user.UserGUID, UserGUID = userAuth.referral, TransactionType = await _context.TransactionTypes.AsQueryable().Where(c => c.TypeName.ToLower().Contains("silver credit")).Select(c => c.TypeCode).AsNoTracking().FirstOrDefaultAsync(), }, }; bool possible = await SilverBankOperations.WithdrawFromBank(62, _context); if (!possible) return 400; DocumentReference docRef = db.Collection(ServerLocation.user_notifications).Document(userAuth.user.UserGUID).Collection(userAuth.user.UserGUID).Document(); Dictionary user = new Dictionary { { "notificationType", "welcome" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", "Welcome to Teso App, as your welcome package we have gifted 52 Silvers Coins for free. You may use them to acquire discount and freebie coupons!!!" }, { "recipient", userAuth.user.UserGUID }, }; batch.Set(docRef, user); DocumentReference docRef2 = db.Collection(ServerLocation.user_notifications).Document(userAuth.referral).Collection(userAuth.referral).Document(); Dictionary user2 = new Dictionary { { "notificationType", "referral" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", "You just earned 10 Silver coins as your referral link was used!!!" }, { "recipient", userAuth.user.UserGUID }, }; batch.Set(docRef2, user2); _context.UserFinances.AddRange(finances); _context.UserTransactions.AddRange(transactions); _context.Referrals.Add(new Referral { Datejoined = DateTime.Now, Referred = userAuth.user.UserGUID, Referrer = userAuth.referral, Rewarded = true, }); } userAuth.user.ThumbnailDp = await UploadedFile(userAuth.user.UserGUID, userAuth.user.ThumbnailDp); _context.UserAuths.Add(userAuth.authentication); _context.TesoUserDetails.Add(userAuth.user); try { await _context.SaveChangesAsync(); await batch.CommitAsync(); } catch (DbUpdateException) { return 400; } return 200; } private bool UserAuthExists(string id) { return _context.UserAuths.Any(e => e.UserGUID == id); } private async Task UploadedFile(string id, string url) { try { string uniqueFileName; uniqueFileName = id + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "dp.jpg"; string filePath = Path.Combine(ServerLocation.displayPicture, uniqueFileName); using (WebClient wc = new WebClient()) wc.DownloadFile(url, filePath); return uniqueFileName; } catch (Exception ex) { Console.WriteLine(ex.ToString()); return null; } } private async Task GetUser(string uid) { return await _context.UserAuths.AsQueryable().FirstOrDefaultAsync(u => u.UserGUID == uid); } public async Task> Authenticate(UserAuth _userData) { var user = await GetUser(_userData.UserGUID); if (user != null) { TesoUserDetail detail = await _context.TesoUserDetails.AsQueryable().Where(usr => usr.UserGUID == user.UserGUID).FirstOrDefaultAsync(); int friends = await _context.Relationships.AsQueryable().Where(t => t.UserGuid == user.UserGUID).CountAsync(); UserFinance finance = await _context.UserFinances.AsQueryable().Where(usr => usr.UserGUID == user.UserGUID).FirstOrDefaultAsync(); if (finance == null) { finance = new UserFinance(); finance.Gold = 0; finance.Silver = 0; } TesoUser tesouser = new TesoUser(); tesouser.userGUID = detail.UserGUID; tesouser.username = detail.Username; tesouser.firstname = detail.Firstname; tesouser.lastname = detail.Surname; tesouser.description = detail.Description; tesouser.email = detail.Email; tesouser.phonenumber = detail.Phonenumber.HasValue ? detail.Phonenumber.Value.ToString() : ""; tesouser.address = detail.Address; tesouser.country = detail.Country; tesouser.gender = detail.Gender; tesouser.DateOfBirth = detail.DateOfBirth; tesouser.gold = finance.Gold.ToString(); tesouser.silver = finance.Silver.ToString(); tesouser.friends = friends.ToString(); tesouser.thumbnail_dp = detail.ThumbnailDp; int timestamp_issued = (int)new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds(); int timestamp_expires = (int)new DateTimeOffset(DateTimeOffset.UtcNow.DateTime.AddDays(14)).ToUnixTimeMilliseconds(); int timestamp_issuednbf = (int)new DateTimeOffset(DateTimeOffset.UtcNow.DateTime.AddMinutes(1)).ToUnixTimeMilliseconds(); //create claims details based on the user information var claims = new[] { new Claim(JwtRegisteredClaimNames.Iat, timestamp_issued.ToString()), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(JwtRegisteredClaimNames.Iss, ServerLocation.issuer), new Claim(JwtRegisteredClaimNames.Exp, timestamp_expires.ToString()), new Claim(JwtRegisteredClaimNames.Nbf, timestamp_issuednbf.ToString()), new Claim(JwtRegisteredClaimNames.Sub, user.UserGUID.ToString()), new Claim("username", user.Username.ToString()), new Claim("userGUID", user.UserGUID.ToString()), new Claim("deviceToken", _userData.DeviceToken), }; //var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(ServerLocation.key)); //var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //var token = new JwtSecurityToken(ServerLocation.issuer, ServerLocation.audience, claims, expires: DateTime.UtcNow.AddDays(14), signingCredentials: signIn); //string tokenwriter = new JwtSecurityTokenHandler().WriteToken(token); string tokenwriter = this.tokenService.GenerateAccessToken(claims); Models.TokenHandler handler = new Models.TokenHandler(); handler.tokenTeso = tokenwriter; handler.user = tesouser; user.DeviceToken = _userData.DeviceToken; _context.Entry(user).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch { } return handler; } else { return BadRequest("Invalid credentials"); } } private bool TesoUserDetailExists(string id) { return _context.TesoUserDetails.Any(e => e.Username == id); } private bool EmailExists(string email) { return _context.TesoUserDetails.Any(e => e.Email == email); } } }