chatr/ChatrServer/Chatr/UserManagement.cs

1231 lines
45 KiB
C#
Raw Permalink Normal View History

2022-08-24 11:34:56 +00:00
using LiteDB;
using Newtonsoft.Json;
using WebSocketSharp;
using WebSocketSharp.Server;
using Tesses.WebServer;
using Chatr;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Net.Http;
namespace Tesses.Chatr.Server
{
public static class DataBase
{
private const string SessionCollectionName = "Sessions";
private const string AccountCollectionName="Accounts";
private const string MessageCollectionName="Messages";
private const string NotificationCollectionName="Notifications";
private const string BotCollectionName = "Bots";
private static LiteDatabase _db;
public static void SetDb(string path)
{
_db=new LiteDatabase(path);
Accounts=_db.GetCollection<Account>(AccountCollectionName);
Sessions=_db.GetCollection<Session>(SessionCollectionName);
Messages=_db.GetCollection<Message>(MessageCollectionName);
Bots=_db.GetCollection<Bot>(BotCollectionName);
Notifications=_db.GetCollection<Notification>(NotificationCollectionName);
}
public static ILiteCollection<Notification> Notifications {get;private set;}
public static ILiteCollection<Account> Accounts {get;private set;}
public static ILiteCollection<Session> Sessions {get;private set;}
public static ILiteCollection<Message> Messages {get;private set;}
//public static ILiteCollection<Notif>? Messages {get;private set;}
public static ILiteCollection<Bot> Bots {get;private set;}
public static void Dispose()
{
_db?.Dispose();
}
}
public class WSConnection : WebSocketBehavior
{
private Account account;
private Bot bot;
protected override void OnClose(CloseEventArgs e)
{
if(bot != null)
{
UserManagement.Bots[bot.Id].Remove(this);
}
if(account != null)
{
UserManagement.Humans[account.Id].Remove(this);
}
}
private void Send(ChatrWSMsg msg)
{
if(this.ConnectionState == WebSocketState.Open)
{
try{
Send(JsonConvert.SerializeObject(msg));
}catch(Exception ex)
{
_=ex;
}
}
}
protected override void OnMessage(MessageEventArgs e)
{
if(e.IsText)
{
var chattrMsg=JsonConvert.DeserializeObject<ChatrWSMsg>(e.Data);
if(chattrMsg!=null){
IPacketData packet;
if(chattrMsg.IsType(PacketType.ClearAll,out packet))
{
if(account != null && bot == null)
{
var clrAll=(ClearAllPacket)packet;
string[] p=clrAll.UserStr.Split(new char[]{'-'},2,StringSplitOptions.RemoveEmptyEntries);
if(p.Length < 1) return;
string human_name = p[0]== "me" ? account.Username : p[0];
if(p.Length ==1)
{
//its human
foreach(var msg in UserManagement.GetMessages(account,human_name).ToList())
{
DataBase.Messages.Delete(msg.Id);
}
if(p[0] != "me")
{
//we send clear all message to other person
ClearAllPacket pkt=new ClearAllPacket();
pkt.UserStr=account.Username;
UserManagement.SendClearAll(pkt);
}
}else{
//its a bot
foreach(var msg in UserManagement.GetMessages(account,human_name,p[1]).ToList())
{
DataBase.Messages.Delete(msg.Id);
}
}
}
}
if(chattrMsg.IsType(PacketType.NotificationEventFire,out packet))
{
if(account != null && bot == null)
{
var noFire=(NotificationEventFirePacket)packet;
Console.WriteLine(JsonConvert.SerializeObject(noFire));
noFire.DestinationUserName = account.Username;
UserManagement.HandleNotificationEventFirePacket(noFire);
}
}
if(chattrMsg.IsType(PacketType.Notification,out packet))
{
if(bot == null || !bot.Permissions.CanSendNotifications || account != null) return; //users can't send notifications
var notification = (NotificationPacket)packet;
if(notification.UserName != "me" && !bot.Permissions.CanSendMessagesToOtherPeople) return;
if(DataBase.Accounts != null && DataBase.Notifications != null && notification != null && !string.IsNullOrWhiteSpace(notification.UserName))
{
var bUser = DataBase.Accounts.FindById(bot.UserId);
if(bUser != null){
long destId = notification.UserName == "me" ? bot.UserId : UserManagement.GetUserId(notification.UserName);
var not= DataBase.Notifications.FindOne(ee=>ee.SourceBotId == bot.Id && ee.SourceUserId == bot.UserId && ee.BotNotificationId == notification.BotNotificationId);
if(not != null)
{
if(!string.IsNullOrWhiteSpace(notification.Body))
{
not.Body=notification.Body;
}else{
not.Body="";
}
not.NotificationButtons.Clear();
foreach(var item in notification.NotificationButtons)
{
not.NotificationButtons.Add(item);
}
not.OnClick=notification.OnClick;
if(!string.IsNullOrWhiteSpace(notification.Title))
{
not.Title=notification.Title;
}else{
not.Title = "";
}
bool isMe = notification.UserName == "me";
string botowneruserName= isMe ? "me" : bUser.Username;
string botusername = bot.BotUserName;
not.BotUserString = $"{botowneruserName}-{botusername}";
DataBase.Notifications.Update(not);
}
else {
Console.WriteLine("NN");
not=new Notification();
if(!string.IsNullOrWhiteSpace(notification.Body))
{
not.Body=notification.Body;
}else{
not.Body="";
}
not.NotificationButtons.Clear();
foreach(var item in notification.NotificationButtons)
{
not.NotificationButtons.Add(item);
}
not.OnClick=notification.OnClick;
if(!string.IsNullOrWhiteSpace(notification.Title))
{
not.Title=notification.Title;
}else{
not.Title = "";
}
if(!string.IsNullOrWhiteSpace(notification.BotNotificationId))
{
not.BotNotificationId=notification.BotNotificationId;
} else{
not.BotNotificationId="";
}
not.SourceBotId = bot.Id;
not.SourceUserId = bot.UserId;
not.DestinationUserId=destId;
bool isMe = notification.UserName == "me";
string botowneruserName= isMe ? "me" : bUser.Username;
string botusername = bot.BotUserName;
not.BotUserString = $"{botowneruserName}-{botusername}";
var bson=DataBase.Notifications.Insert(not);
not.Id=bson.AsInt64;
notification.Id=bson.AsInt64;
}
UserManagement.SendNotification(not);
}
}
}
if(chattrMsg.IsType(PacketType.AuthenticateUser,out packet))
{
var authUser=(AuthenticationUserPacket)packet;
//authenticate this as a user
var res=UserManagement.Authenticate(authUser.SessionId);
if(res.Success && res.Account !=null)
{
UserManagement.Humans.Add(res.Account.Id,this);
account=res.Account;
}else{
}
}
if(chattrMsg.IsType(PacketType.AuthenticateBot,out packet))
{
var authUser=(AuthenticateBotPacket)packet;
//authenticate this as a user
var res=UserManagement.AuthenticateApiKey(authUser.ApiKey);
if(res.Success && res.Bot !=null)
{
UserManagement.Bots.Add(res.Bot.Id,this);
bot=res.Bot;
}
}
if(chattrMsg.IsType(PacketType.Message,out packet))
{
var msg = (MessagePacket)packet;
if(!string.IsNullOrWhiteSpace(msg.UserStr)){
var usrs=msg.UserStr.Split(new char[]{'-'},2);
if(usrs.Length >= 1)
{
string user = usrs[0];
string bot=null;
if(usrs.Length == 2)
{
bot = usrs[1];
}
Message msg0=new Message();
if(msg0.CreationTime.Year == 1970) msg0.CreationTime=DateTime.Now;
if(!string.IsNullOrWhiteSpace(msg.Content))
msg0.Content = msg.Content;
else
msg0.Content = "[No Body]";
if(this.bot != null)
{
msg0.IsFromBot=true;
msg0.SourceBotId = this.bot.Id;
msg0.SourceUserId = this.bot.UserId;
if(!string.IsNullOrWhiteSpace(bot))
{
msg0.IsToBot=true;
if(!this.bot.Permissions.OthersCanReceiveMessages) return;
if(user == "me")
{
msg0.DestinationUserId = msg0.SourceUserId;
msg0.DestinationBotId = UserManagement.GetBotId(msg0.SourceUserId,bot);
}else{
msg0.DestinationUserId= UserManagement.GetUserId(user);
msg0.DestinationBotId= UserManagement.GetBotId(user,bot);
}
UserManagement.SendMessage(msg0);
}else{
msg0.IsToBot=false;
if(user == "me")
{
msg0.DestinationUserId=msg0.SourceUserId;
}else{
if(!this.bot.Permissions.CanSendMessagesToOtherPeople) return;
msg0.DestinationUserId= UserManagement.GetUserId(user);
}
UserManagement.SendMessage(msg0);
}
}
if(this.account != null)
{
msg0.IsFromBot=false;
msg0.SourceUserId = this.account.Id;
if(!string.IsNullOrWhiteSpace(bot))
{
msg0.IsToBot=true;
if(user == "me")
{
msg0.DestinationUserId = msg0.SourceUserId;
msg0.DestinationBotId= UserManagement.GetBotId(msg0.DestinationUserId,bot);
}else{
msg0.DestinationUserId= UserManagement.GetUserId(user);
msg0.DestinationBotId= UserManagement.GetBotId(user,bot);
}
Bot bt;
if(DataBase.Bots != null && (bt=DataBase.Bots.FindById(msg0.DestinationBotId)) != null)
{
if(!bt.Permissions.CanGetMessages)
{
return;
}
}
UserManagement.SendMessage(msg0);
}else{
msg0.IsToBot=false;
if(user == "me")
{
msg0.DestinationUserId=msg0.SourceUserId;
}else{
msg0.DestinationUserId= UserManagement.GetUserId(user);
}
UserManagement.SendMessage(msg0);
}
}
}
}
}
}
}
}
public void Push(ClearAllPacket pkt)
{
Send(new ChatrWSMsg(pkt));
}
public void Push(Message msg)
{
var userStr = UserManagement.GetHashTextFromMessage(msg,true);
var nameStr = UserManagement.GetNameTextFromMessage(msg,true);
var msgData = msg.Content;
var creationTime = msg.CreationTime.ToString("R");
ChatrWSMsg packet=new ChatrWSMsg();
var mpd=new MessagePacket();
mpd.Content=msgData;
mpd.CreationTime=creationTime;
mpd.UserStr=userStr;
mpd.Name=nameStr;
//mpd.Name
packet.SetPacketData(mpd);
//the json packet
Send(packet);
}
public void Push(NotificationEventFirePacket packet)
{
var ppacket=new ChatrWSMsg();
ppacket.SetPacketData(packet);
Send(ppacket);
}
public void Push(Notification notification)
{
if(DataBase.Bots==null || DataBase.Accounts == null) return;
/*
object packet=new{
PacketType="Notification",
Data=new{
BotName = notification.BotName,
Title=notification.Title,
Body=notification.Body,
OnClick=notification.OnClick.ToObject(notification.Id),
}
};
//the json packet
Send(packet);
*/
NotificationPacket packet=new NotificationPacket();
packet.Body=notification.Body;
var bot = DataBase.Bots.FindOne(e=>e.Id==notification.SourceBotId);
var usr = DataBase.Accounts.FindOne(e=>e.Id ==notification.SourceUserId);
if(bot != null && usr != null)
{
packet.BotName = bot.BotName;
packet.BotOwnerName = usr.Name;
packet.BotOwnerUserName =usr.Username;
packet.BotNotificationId=notification.BotNotificationId;
packet.Id=notification.Id;
packet.NotificationButtons=notification.NotificationButtons;
packet.OnClick=notification.OnClick;
packet.Title =notification.Title;
packet.BotUserString = notification.BotUserString;
var ppacket=new ChatrWSMsg();
ppacket.SetPacketData(packet);
Send(ppacket);
}
//packet.BotName=notification.SourceBotId
}
}
public static class UserManagement
{
internal static Dictionary<long,List<WSConnection>> Humans=new Dictionary<long, List<WSConnection>>();
internal static Dictionary<long,List<WSConnection>> Bots=new Dictionary<long, List<WSConnection>>();
internal static HttpClient clt=new HttpClient();
internal static Dictionary<string,OTA> _otaCodes=new Dictionary<string, OTA>();
private static void SendHttpRequest(Dictionary<string,string> dict)
{
//MET
//HDR
//URL
//BDY
Dictionary<string,List<string>> headers=new Dictionary<string, List<string>>();
string method="GET";
string url="http://example.com/";
byte[] body=new byte[0];
foreach(var d in dict)
{
if(d.Key == "MET")
{
method=d.Value;
}else if(d.Key == "URL")
{
url = d.Value;
}else if(d.Key == "BDY")
{
body = Convert.FromBase64String(d.Value);
}else if(d.Key.StartsWith("HDR"))
{
string[] key= d.Key.Substring(3).Split(new char[]{':'},2);
headers.Add(key[0],d.Value);
}
}
HttpRequestMessage msg=new HttpRequestMessage(new HttpMethod(method),url);
foreach(var h in headers)
{
msg.Headers.Add(h.Key,h.Value);
}
if(body.Length > 0)
{
msg.Content=new ByteArrayContent(body);
}
clt.SendAsync(msg).GetAwaiter().GetResult().Dispose();
}
public static void HandleNotificationEventFirePacket(NotificationEventFirePacket packet)
{
if(DataBase.Notifications != null)
{
var p=DataBase.Notifications.FindOne(e=>e.BotUserString ==packet.BotUserString && e.BotNotificationId == packet.BotNotificationId);
if(p != null)
{
if(string.IsNullOrWhiteSpace(packet.Button))
{
//onclick
switch(p.OnClick.Type)
{
case NotificationEventType.CallApiFromServer:
SendHttpRequest(p.OnClick.Data);
break;
case NotificationEventType.SendCallbackToBot:
SendNotificationEvent(packet);
break;
}
}else{
try{
var p0 = p.NotificationButtons.Find(e=>{
return e.Text == packet.Button;
});
if(p0==null) return;
switch(p0.Event.Type)
{
case NotificationEventType.CallApiFromServer:
SendHttpRequest(p0.Event.Data);
break;
case NotificationEventType.SendCallbackToBot:
SendNotificationEvent(packet);
break;
}
}catch(Exception ex)
{
_=ex;
}
}
}
}
}
public static bool DefaultVerificationStatus { get; set; }
public static bool AllowLoginAsAnnonymous { get; set; }
public static RegistrationResult RegisterAccount(string name,string username,string email,string password)
{
if(username.Equals("_anonymous") || email.Equals("anonymous@example.com"))
{
return new RegistrationResult("Can't Register Anonymous");
}
if(IsValidPassword(password))
{
var users=DataBase.Accounts;
if(users != null){
var user =users.FindOne(e=>e.Username == username);
if(user != null)
{
var res=new RegistrationResult("Username Exists");
return res;
}
user = users.FindOne(e=>e.Email == email);
if(user != null)
{
var res=new RegistrationResult("Email Exists");
return res;
}
bool oobe=users.LongCount() == 0;
Account a =new Account();
a.Username = username;
a.SetPassword(password,true);
a.Name = name;
a.Email=email;
a.Verified=UserManagement.DefaultVerificationStatus;
a.IsAdmin = oobe;
a.ShowUserNameToAnyBody=oobe;
if(a.IsValid())
{
users.Insert(a);
if(oobe)
{
//Register Anonymous
Account a2=new Account();
a2.IsAnonymous=true;
a2.IsAdmin=false;
a2.Verified=true;
a2.Username="_anonymous";
a2.Email = "anonymous@example.com";
a2.ShowUserNameToAnyBody=true;
a2.Name="Chatr Anonymous User";
a2.SetPassword("4209enabled",true); //dummy password would be 4209disabled when disabled
users.Insert(a2);
}
return new RegistrationResult(a);
}
return new RegistrationResult("Invalid sign up details");
}
return new RegistrationResult("Database Error: Accounts is null");
}
return new RegistrationResult("Invalid Password");
}
internal static void Logout(string session_id)
{
var sessions=DataBase.Sessions;
if(!string.IsNullOrWhiteSpace(session_id) && sessions!=null)
{
var session=sessions.FindOne(e=>e.SessionId==session_id);
if(session != null)
{
sessions.Delete(session.Id);
}
}
}
static Dictionary<long,UserOptions> _opt=new Dictionary<long, UserOptions>();
public static UserOptions GetUserOptions(Account account)
{
if(_opt.ContainsKey(account.Id))
{
return _opt[account.Id];
}
return new UserOptions(account);
}
public static void SetUserOptions(UserOptions options,ServerContext ctx)
{
options.Set(ctx);
}
public static AuthenticationResult Authenticate(string session_id)
{
var sessions=DataBase.Sessions;
if(sessions == null) return new AuthenticationResult("Database Error: Sessions is null");
var users=DataBase.Accounts;
if(users == null) return new AuthenticationResult("Database Error: Accounts is null");
foreach(var session in sessions.FindAll())
{
if(session.SessionId.Equals(session_id) && DateTime.Now < session.Expires)
{
var user=users.FindById(session.UserId);
if(user != null)
{
return new AuthenticationResult(user,session);
}
return new AuthenticationResult("User Removed");
}
}
return new AuthenticationResult("No valid session");
}
public static string CreateAnotherSession(string session_id,DateTime expires)
{
var sessions=DataBase.Sessions;
if(sessions == null) return null;
var users=DataBase.Accounts;
if(users == null) return null;
var session=sessions.FindOne(e=>e.SessionId==session_id);
if(session != null && DateTime.Now < session.Expires)
{
var user=users.FindById(session.UserId);
if(user != null)
{
Session session2=new Session();
session2.Expires=expires;
session2.RememberMe=true;
session2.Created=DateTime.Now;
session2.SessionId = Session.GetNewId();
session2.UserId=session.UserId;
sessions.Insert(session2);
return session2.SessionId;
}
}
return null;
}
private static string CreateSession(Account user,DateTime expire,bool rememberMe)
{
var sessions=DataBase.Sessions;
if(sessions == null) return null;
string id= Session.GetNewId();
Session s=new Session();
s.Expires=expire;
s.SessionId=id;
s.UserId=user.Id;
s.RememberMe=rememberMe;
s.Created=DateTime.Now;
sessions.Insert(s);
return id;
}
public static Account GetAnonymous()
{
if(DataBase.Accounts != null)
{
var res=DataBase.Accounts.FindOne(e=>e.IsAnonymous);
if(res!=null) return res;
}
return null;
}
public static LoginResult Login(string username,string password,bool rememberMe)
{
LoginResult res=new LoginResult();
res.Success=false;
var users=DataBase.Accounts;
if(users == null || username == "_anonymous" /*prevent logging in as lovely _anonymous account*/) return res;
var user=users.FindOne(e=>e.Username == username);
if(user != null && user.IsCorrectPassword(password))
{
DateTime expire=rememberMe ? DateTime.Now.AddYears(1) : DateTime.Now.AddHours(2);
res.Success=true;
res.Account=user;
res.Expires=expire;
res.SessionId = CreateSession(user,expire,rememberMe);
}
return res;
}
public static string GetNameTextFromMessage(Message msg,bool fromMe)
{
if(!msg.IsFromBot && !msg.IsToBot)
{
//person to person
if(msg.DestinationUserId == msg.SourceUserId) return "me";
if(DataBase.Accounts != null){
if(!fromMe)
{
//to me from username
var user = DataBase.Accounts.FindById(msg.DestinationUserId);
if(user != null)
{
return user.Name;
}
}else{
var user = DataBase.Accounts.FindById(msg.SourceUserId);
if(user != null)
{
return user.Name;
}
}
}
}else{
if(DataBase.Bots != null)
{
if(msg.DestinationUserId == msg.SourceUserId)
{
//me-botname
if(msg.IsFromBot ^ msg.IsToBot)
{
if(msg.IsFromBot)
{
//get bot for from
var bot=DataBase.Bots.FindById(msg.SourceBotId);
if(bot != null)
return $"{bot.BotName} (My Bot)";
}else{
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
if(bot != null)
return $"{bot.BotName} (My Bot)";
}
} // bot to bot communication not supported in ui if at all
}else{
if(DataBase.Accounts != null){
//the bot must not be yours
if(msg.IsFromBot ^ !fromMe)
{
var a = DataBase.Accounts.FindById(msg.SourceUserId);
var bot=DataBase.Bots.FindById(msg.SourceBotId);
if(bot != null && a != null)
return $"{bot.BotName} ({a.Name}'s Bot)";
//return $"{a.Username}-{bot.BotUserName}";
// {userName}-{botname}
}else if(msg.IsToBot ^ fromMe)
{
var a = DataBase.Accounts.FindById(msg.DestinationUserId);
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
if(bot != null && a != null)
return $"{bot.BotName} ({a.Name}'s Bot)";
//return $"{a.Username}-{bot.BotUserName}";
}
}
}
}
}
return "";
}
public static string GetHashTextFromMessage(Message msg,bool fromMe) //true if you are ws to dest, false if loading my msg from data base
{
//from me = true
//msg.Source will be considered me msg.Destination will be username
//from me = false
//msg.Destination will be considered username, destination will be me
if(!msg.IsFromBot && !msg.IsToBot)
{
//person to person
if(msg.DestinationUserId == msg.SourceUserId) return "me";
if(DataBase.Accounts != null){
if(!fromMe)
{
//to me from username
var user = DataBase.Accounts.FindById(msg.DestinationUserId);
if(user != null)
{
return user.Username;
}
}else{
var user = DataBase.Accounts.FindById(msg.SourceUserId);
if(user != null)
{
return user.Username;
}
}
}
}else{
if(DataBase.Bots != null)
{
if(msg.DestinationUserId == msg.SourceUserId)
{
//me-botname
if(msg.IsFromBot ^ msg.IsToBot)
{
if(msg.IsFromBot)
{
//get bot for from
var bot=DataBase.Bots.FindById(msg.SourceBotId);
if(bot != null)
return $"me-{bot.BotUserName}";
}else{
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
if(bot != null)
return $"me-{bot.BotUserName}";
}
} // bot to bot communication not supported in ui if at all
}else{
if(DataBase.Accounts != null){
//the bot must not be yours
if(msg.IsFromBot ^ !fromMe)
{
var a = DataBase.Accounts.FindById(msg.SourceUserId);
var bot=DataBase.Bots.FindById(msg.SourceBotId);
if(bot != null && a != null)
return $"{a.Username}-{bot.BotUserName}";
// {userName}-{botname}
}else if(msg.IsToBot ^ fromMe)
{
var a = DataBase.Accounts.FindById(msg.DestinationUserId);
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
if(bot != null && a != null)
return $"{a.Username}-{bot.BotUserName}";
}
}
}
}
}
return "";
}
//this doesn't check whether message is legit, it is done somewhere else
public static void SendMessage(Message msg)
{
msg.CreationTime=DateTime.Now;
if(DataBase.Messages != null)
{
//put msg in database
DataBase.Messages.Insert(msg); //easy as pie
//send to user over ws, somewhat harder
if(msg.IsToBot)
{
if(Bots.ContainsKey(msg.DestinationBotId))
{
foreach(var bot in Bots[msg.DestinationBotId])
{
bot.Push(msg);
}
}
}else{
Account tmpAcc;
if(DataBase.Accounts != null && ( tmpAcc = DataBase.Accounts.FindById(msg.DestinationUserId))!= null && tmpAcc.IsHidden(msg.SourceUserId,msg.IsFromBot ? msg.SourceBotId : -1) ) return;//impl hidden accounts and stuff
if(Humans.ContainsKey(msg.DestinationUserId))
{
foreach(var human in Humans[msg.DestinationUserId])
{
human.Push(msg);
}
}
}
}
}
public static void SendNotification(Notification notification)
{
if(DataBase.Notifications != null)
{
if(Humans.ContainsKey(notification.DestinationUserId))
{
foreach(var item in Humans[notification.DestinationUserId])
{
item.Push(notification);
}
}
}
}
public static void SendNotificationEvent(NotificationEventFirePacket notification)
{
if(DataBase.Notifications != null && !string.IsNullOrWhiteSpace(notification.BotUserString) && !string.IsNullOrWhiteSpace(notification.SourceUserName))
{
var not=notification.BotUserString.Split(new char[]{'-'},2);
if(not.Length < 2) return;
string user=not[0];
string bot = not[1];
if(user == "me")
{
user = notification.SourceUserName;
}
long botId = GetBotId(user,bot);
if(Bots.ContainsKey(botId))
{
foreach(var item in Bots[botId])
{
item.Push(notification);
}
}
}
}
public static long GetUserId(string user)
{
Account a;
if(DataBase.Accounts != null && (a=DataBase.Accounts.FindOne(e=>e.Username == user)) != null )
return a.Id;
return -1;
}
public static long GetBotId(string user,string bot)
{
Bot b;
if(DataBase.Bots != null && (b=DataBase.Bots.FindOne(e=>e.BotUserName == bot && e.UserId== GetUserId(user))) != null)
return b.Id;
return -1;
}
public static long GetBotId(long user,string bot)
{
Bot b;
if(DataBase.Bots != null && (b=DataBase.Bots.FindOne(e=>e.BotUserName == bot && e.UserId== user)) != null)
return b.Id;
return -1;
}
public static IEnumerable<Bot> GetMyBots(Account account,bool censored=true)
{
if(DataBase.Bots != null)
{
foreach(var bot in DataBase.Bots.Find(e=>e.UserId==account.Id))
{
if(censored && account.IsHidden(account.Id,bot.Id)) continue;
yield return bot;
}
}
yield break;
}
public static IEnumerable<Bot> GetBotsWithMe(Account account,Account other,bool censored=true)
{
if(censored && account.IsHidden(other.Id,-1)) yield break;
List<long> ids=new List<long>();
if(DataBase.Messages != null && DataBase.Bots != null)
{
foreach(var msg in DataBase.Messages.FindAll())
{
var e=msg;
if(!((e.DestinationUserId == other.Id && e.SourceUserId ==account.Id && !e.IsFromBot && e.IsToBot ) ^ (e.DestinationUserId == account.Id && e.IsFromBot && !e.IsToBot && e.SourceUserId == other.Id) )) continue;
if(msg.SourceUserId == account.Id)
{
if(!ids.Contains(msg.DestinationBotId)) ids.Add(msg.DestinationBotId);
}else{
if(!ids.Contains(msg.SourceBotId)) ids.Add(msg.SourceBotId);
}
}
foreach(var id in ids)
{
if( censored|| account.IsHidden(other.Id,id)) continue;
var res=DataBase.Bots.FindById(id);
if(res != null)
yield return res;
}
}
yield break;
}
public static IEnumerable<Account> GetUserWithMe(Account account,bool censored=true)
{
List<long> ids=new List<long>();
if(DataBase.Messages != null && DataBase.Accounts != null)
{
foreach(var msg in DataBase.Messages.FindAll())
{
var e=msg;
if(!(e.SourceUserId ==account.Id ^ e.DestinationUserId == account.Id )) continue;
if(msg.SourceUserId == account.Id)
{
if(!ids.Contains(msg.DestinationUserId)) ids.Add(msg.DestinationUserId);
}else{
if(!ids.Contains(msg.SourceUserId)) ids.Add(msg.SourceUserId);
}
}
foreach(var usr in DataBase.Accounts.Find(e=>e.ShowUserNameToAnyBody==true))
{
if(!ids.Contains(usr.Id))
{
ids.Add(usr.Id);
}
}
foreach(var id in ids)
{
if(censored && account.IsHidden(id,-1)) continue;
var res=DataBase.Accounts.FindById(id);
if(res != null)
yield return res;
}
}
yield break;
}
public static IEnumerable<Message> GetMessages(Account account,string user=null,string bot=null,bool censored=true)
{
if(DataBase.Messages != null)
{
if(string.IsNullOrWhiteSpace(user) && string.IsNullOrWhiteSpace(bot))
{
//you
foreach(var msg in DataBase.Messages.Find(e=> e.IsFromBot == false && e.IsToBot == false && e.SourceUserId == account.Id && e.DestinationUserId == account.Id))
{
yield return msg;
}
}
else if(string.IsNullOrWhiteSpace(bot) && !string.IsNullOrWhiteSpace(user))
{
//a user
var userId=GetUserId(user);
if(censored && account.IsHidden(userId,-1)) yield break;
foreach(var msg in DataBase.Messages.Find(e=>e.IsFromBot == false && e.IsToBot==false && ((e.SourceUserId == userId && e.DestinationUserId == account.Id) || (e.SourceUserId == account.Id && e.DestinationUserId == userId))))
{
yield return msg;
}
}else if(!string.IsNullOrWhiteSpace(bot) && string.IsNullOrWhiteSpace(user))
{
//my bots
var botId = GetBotId(account.Id,bot);
if(censored && account.IsHidden(account.Id,botId)) yield break;
foreach(var msg in DataBase.Messages.Find(e=>(
(e.SourceUserId == account.Id && e.IsFromBot==true && e.IsToBot==false && e.SourceBotId == botId && e.DestinationUserId ==account.Id) ||
(e.DestinationUserId == account.Id && e.IsToBot==true && e.IsFromBot == false && e.SourceUserId == account.Id)
)))
{
yield return msg;
}
}
else if(!string.IsNullOrWhiteSpace(bot) && !string.IsNullOrWhiteSpace(user)){
// a bot
var userId = GetUserId(user);
var botId = GetBotId(userId,bot);
if(account.IsHidden(userId,botId)) yield break;
foreach(var msg in DataBase.Messages.Find(e=>(
(e.SourceUserId == userId && e.IsFromBot==true && e.IsToBot==false && e.SourceBotId == botId && e.DestinationUserId == account.Id) ||
(e.DestinationUserId == userId && e.IsToBot==true && e.IsFromBot == false && e.SourceUserId == account.Id)
)))
{
yield return msg;
}
}
}
yield break;
}
public static AuthenticationBotResult AuthenticateApiKey(string apiKey)
{
if(DataBase.Bots == null)return new AuthenticationBotResult("Database Error: Bots is null");
//authenticate bot
var bot=DataBase.Bots.FindOne(e=>e.ApiKey == apiKey);
if(bot != null){
return new AuthenticationBotResult(bot);
}
return new AuthenticationBotResult("Bot Not found for apiKey");
}
public static string GenerateApiKey(Account user,Bot bot)
{
if(DataBase.Bots == null)return null;
string apiKey;
do{
apiKey=Account.GetNewSalt();
} while(DataBase.Bots.FindOne(e=>e.ApiKey == apiKey) != null);
bot.ApiKey=apiKey;
bot.UserId=user.Id;
DataBase.Bots.Insert(bot);
return apiKey;
}
public static bool IsValidPassword(string password)
{
if(password.Length < 8) return false; //need a longer password
if(password.StartsWith("password",StringComparison.OrdinalIgnoreCase)) return false; //prevents password password1 etc
int num = 0;
char lastChar='\0';
foreach(var c in password) //prevents 12345678
{
if(c+1 == lastChar)
{num++;}
else if(c-1 == lastChar) {num++;} else {num=0;}
lastChar=c;
if(num > 5) return false;
}
return true;
}
internal static bool GetAuthCode(string key, out string session)
{
session="";
if(_otaCodes.ContainsKey(key))
{
if(_otaCodes[key].Expires > DateTime.Now)
{
session=_otaCodes[key].SessionId;
return true;
}
_otaCodes.Remove(key);
}
return false;
}
private static string GetRandOta()
{
string id=Session.GetNewId().Replace("=","ee").Replace("+","je").Replace("/","42");
return id;
}
internal static string CreateOTA(string sessionId)
{
string ota=GetRandOta();
while(_otaCodes.ContainsKey(ota))
{
ota=GetRandOta();
}
OTA o=new OTA();
o.Expires=DateTime.Now.AddMinutes(10);
o.SessionId = sessionId;
_otaCodes.Add(ota,o);
return ota;
}
internal static void SendClearAll(ClearAllPacket pkt)
{
var uid= UserManagement.GetUserId(pkt.UserStr);
if(Humans.ContainsKey(uid))
{
foreach(var item in Humans[uid])
{
item.Push(pkt);
}
}
}
}
internal class OTA
{
public string SessionId {get;set;}
public DateTime Expires {get;set;}
}
}