Backend for the Teso project written in 2022
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
17 KiB

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/facebookauth")]
[ApiController]
public class FacebookAuthController : ControllerBase
{
public IConfiguration _configuration;
private readonly TESOContext _context;
private FirestoreDb db;
readonly ITokenService tokenService;
public FacebookAuthController(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<ActionResult<Models.TokenHandler>> Post(FacebookUser 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() == "facebook").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() == "facebook").Select(f => f.TypeCode).FirstOrDefaultAsync();
string[] splitted = user.Email.Split("@"[0]);
auth.DeviceToken = user.devicetoken;
return await Authenticate(auth);
}
}
public async Task<int> 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(5, _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<string, object> user = new Dictionary<string, object>
{
{ "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<UserFinance> finances = new List<UserFinance>{
new UserFinance
{
Gold = 0,
Silver = 52,
UserGUID = userAuth.user.UserGUID,
},
new UserFinance
{
Gold = 0,
Silver = 10,
UserGUID = userAuth.referral,
},
};
List<UserTransaction> transactions = new List<UserTransaction>() {
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<string, object> user = new Dictionary<string, object>
{
{ "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<string, object> user2 = new Dictionary<string, object>
{
{ "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<string> 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<UserAuth> GetUser(string uid)
{
return await _context.UserAuths.AsQueryable().FirstOrDefaultAsync(u => u.UserGUID == uid);
}
public async Task<ActionResult<Models.TokenHandler>> 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.DateOfBirth = detail.DateOfBirth;
tesouser.gender = detail.Gender;
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);
}
}
}