using FSO.Server.Api.Core.Services; using FSO.Server.Api.Core.Utils; using FSO.Server.Common; using FSO.Server.Common.Config; using FSO.Server.Database.DA; using FSO.Server.Domain; using FSO.Server.Servers.Api.JsonWebToken; using Microsoft.AspNetCore.Http; using System; using System.Collections.Specialized; using System.Linq; using System.Security; namespace FSO.Server.Api.Core { public class Api : ApiAbstract { public static Api INSTANCE; public IDAFactory DAFactory; public ApiConfig Config; public JWTFactory JWT; public Shards Shards; public IGluonHostPool HostPool; public IUpdateUploader UpdateUploader; public IUpdateUploader UpdateUploaderClient; public GithubConfig Github; public Api() { INSTANCE = this; } public void Init(NameValueCollection appSettings) { Config = new ApiConfig(); Config.Maintainance = bool.Parse(appSettings["maintainance"]); Config.AuthTicketDuration = int.Parse(appSettings["authTicketDuration"]); Config.Regkey = appSettings["regkey"]; Config.Secret = appSettings["secret"]; Config.UpdateUrl = appSettings["updateUrl"]; Config.CDNUrl = appSettings["cdnUrl"]; Config.NFSdir = appSettings["nfsdir"]; Config.UseProxy = bool.Parse(appSettings["useProxy"]); Config.UpdateID = (appSettings["updateID"] == "") ? (int?)null : int.Parse(appSettings["updateID"]); Config.BranchName = appSettings["branchName"] ?? "beta"; // new smtp config vars if (appSettings["smtpHost"]!=null&& appSettings["smtpUser"]!=null&& appSettings["smtpPassword"]!=null&& appSettings["smtpPort"]!=null) { Config.SmtpEnabled = true; Config.SmtpHost = appSettings["smtpHost"]; Config.SmtpUser = appSettings["smtpUser"]; Config.SmtpPassword = appSettings["smtpPassword"]; Config.SmtpPort = int.Parse(appSettings["smtpPort"]); } JWT = new JWTFactory(new JWTConfiguration() { Key = System.Text.UTF8Encoding.UTF8.GetBytes(Config.Secret) }); DAFactory = new MySqlDAFactory(new Database.DatabaseConfiguration() { ConnectionString = appSettings["connectionString"] }); Shards = new Shards(DAFactory); Shards.AutoUpdate(); } public JWTUser RequireAuthentication(HttpRequest request) { JWTUser result; if (!string.IsNullOrEmpty(request.Headers["Authorization"])) { result = JWT.DecodeToken(GetAuthParam(request.Headers["Authorization"])); } else { var cookies = request.Cookies; if (cookies == null) throw new SecurityException("Unable to find cookie"); var cookie = cookies["fso"]; if (string.IsNullOrEmpty(cookie)) { throw new SecurityException("Unable to find cookie"); } result = JWT.DecodeToken(cookie); } if (result == null) { throw new SecurityException("Invalid token"); } return result; } public string GetAuthParam(string auth) { var ind = auth.IndexOf(' '); if (ind == -1) return auth; return auth.Substring(ind + 1); } /// /// Sends an email to a user to tell them that they're banned. ;( /// /// /// /// public void SendBanMail(string username, string email, uint end_date) { ApiMail banMail = new ApiMail("MailBan"); var date = end_date == 0 ? "Permanent ban" : Epoch.ToDate(end_date).ToString(); banMail.AddString("username", username); banMail.AddString("end", date); banMail.Send(email, "Banned from ingame"); } /// /// Sends an email to a user saying that the registration went OK. /// /// /// public void SendEmailConfirmationOKMail(string username, string email) { ApiMail confirmOKMail = new ApiMail("MailRegistrationOK"); confirmOKMail.AddString("username", username); confirmOKMail.Send(email, "Welcome to FreeSO, " + username + "!"); } /// /// Sends an email to a a new user with a token to create their user. /// /// /// /// /// /// public bool SendEmailConfirmationMail(string email, string token, string confirmation_url, uint expires) { ApiMail confirmMail = new ApiMail("MailRegistrationToken"); confirmation_url = confirmation_url.Replace("%token%", token); confirmMail.AddString("token", token); confirmMail.AddString("expires", Epoch.HMSRemaining(expires)); confirmMail.AddString("confirmation_url", confirmation_url); return confirmMail.Send(email, "Verify your FreeSO account"); } /// /// Sends an email to a user with a token to reset their password. /// /// /// /// /// /// /// public bool SendPasswordResetMail(string email, string username, string token, string confirmation_url, uint expires) { ApiMail confirmMail = new ApiMail("MailPasswordReset"); confirmation_url = confirmation_url.Replace("%token%", token); confirmMail.AddString("token", token); confirmMail.AddString("expires", Epoch.HMSRemaining(expires)); confirmMail.AddString("confirmation_url", confirmation_url); return confirmMail.Send(email, "Password Reset for " + username); } /// /// Sends a password change success email to a user. /// /// /// /// public bool SendPasswordResetOKMail(string email, string username) { ApiMail confirmMail = new ApiMail("MailPasswordResetOK"); confirmMail.AddString("username", username); return confirmMail.Send(email, "Your account password was reset"); } public void DemandModerator(JWTUser user) { if (!user.Claims.Contains("moderator")) throw new Exception("Requires Moderator level status"); } public void DemandAdmin(JWTUser user) { if (!user.Claims.Contains("admin")) throw new Exception("Requires Admin level status"); } public void DemandModerator(HttpRequest request) { DemandModerator(RequireAuthentication(request)); } public void DemandAdmin(HttpRequest request) { DemandAdmin(RequireAuthentication(request)); } /// /// Changes a user's password. /// /// /// public void ChangePassword(uint user_id, string new_password) { using (var da = DAFactory.Get()) { var passhash = PasswordHasher.Hash(new_password); var authSettings = new Database.DA.Users.UserAuthenticate(); authSettings.scheme_class = passhash.scheme; authSettings.data = passhash.data; authSettings.user_id = user_id; da.Users.UpdateAuth(authSettings); } } /// /// Inserts a brand new user in db. /// /// /// /// /// /// public Database.DA.Users.User CreateUser(string username, string email, string password, string ip) { using (var da = DAFactory.Get()) { var userModel = new Database.DA.Users.User(); userModel.username = username; userModel.email = email; userModel.is_admin = false; userModel.is_moderator = false; userModel.user_state = Database.DA.Users.UserState.valid; userModel.register_date = Epoch.Now; userModel.is_banned = false; userModel.register_ip = ip; userModel.last_ip = ip; var passhash = PasswordHasher.Hash(password); var authSettings = new Database.DA.Users.UserAuthenticate(); authSettings.scheme_class = passhash.scheme; authSettings.data = passhash.data; try { var userId = da.Users.Create(userModel); authSettings.user_id = userId; da.Users.CreateAuth(authSettings); return da.Users.GetById(userId); } catch (Exception) { return null; } } } } }