Full completed project

This commit is contained in:
2025-02-10 12:37:33 +00:00
commit b9abff8012
229 changed files with 16866 additions and 0 deletions

View File

@@ -0,0 +1 @@
__all__ = ['config','database', 'datetime']

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,85 @@
import configparser
from modules.track.logging import log
path = "data/config.ini"
def create():
try:
file = open(path, 'r')
log("INFO", "Config already exists")
return
except FileNotFoundError as e:
log("INFO", "Creating config file")
pass
config = configparser.ConfigParser()
config.add_section('authorisation')
# change this to a randomly generated string
config.set('authorisation', 'AdminKey', 'secret')
config.set('authorisation', 'RegistrationKey', 'secret')
config.set('authorisation', 'UsernameMaxLength', '20')
config.set('authorisation', 'UsernameMinLength', '5')
config.set('authorisation', 'PasswordMaxLength', '30')
config.set('authorisation', 'PasswordMinLength', '5')
config.set('authorisation', 'TokenExpiryTime', '2592000')
config.add_section('database')
config.set('database', 'Path', 'data/database.db')
config.set('database', 'Encrypt', 'false')
config.set('database', 'ShamirSecretSharing', 'false')
config.set('database', 'NumberOfShares', '5')
config.set('database', 'MinimumShares', '3')
config.set('database', 'KeyPath', 'data/key.txt')
config.set('database', 'EncryptedPath', 'data/.cryptdatabase.db')
config.set('database', 'EncryptionConfigPath', 'data/encryptconfig.txt')
config.set('database', 'SaltPath', 'data/.salt.txt')
config.set('database', 'SharesPath', 'data/shares/')
config.add_section('user')
config.set('user', 'DefaultLevel', 'member')
config.set('user', 'DefaultOccupationID', 'Null')
config.add_section('posts')
config.set('posts', 'PostTimeLimit', '5') # miniutes
config.set('posts', 'DayStart', '9') #24 hour time
config.set('posts', 'DayEnd', '17') #24 hour time
config.add_section('notifications')
config.set('notifications', 'DefaultExpireTime', '604800')
config.set('notifications', 'ntfyUrl', 'https://ntfy.example.com')
config.add_section('networking')
config.set('networking', 'Port', '9999')
config.add_section('miscellaneous')
config.set('miscellaneous', 'ServerCode', '12345')
with open(path, 'w') as configfile:
config.write(configfile)
log("INFO", "Created config file")
def read(section, key, *args, **kwargs):
config = configparser.ConfigParser()
config.read(path)
if section not in config:
return None
if key not in config[section]:
return None
info = config[section][key]
if info == "false":
info = False
if info == "true":
info = True
return info
def main():
create()
info = read("users", "DefaultOccupation")
print(info)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,693 @@
import sqlite3
import os
import ctypes
import pathlib
import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
# db encrypt
from cryptography.fernet import Fernet
#from pysqlcipher3 import dbapi2 as sqlite3
# db encrypt
from modules.track.logging import log
from modules.data.config import read as config_read
from modules.algorithms.uuid import generate as uuid_generate
class connect():
def __init__(self):
self.path = config_read("database", "Path")
def create(self, obj):
self.con = sqlite3.connect(self.path)
self.cur = self.con.cursor()
if obj != None:
obj.con = self.con
obj.cur = self.cur
def commit(self):
self.con.commit()
def close(self):
self.con.commit()
self.con.close()
def execute(self, command, values=None):
cur = self.con.cursor()
cur.execute(command, values)
self.close()
# Table creation
class create():
def __init__(self):
self.path = config_read("database", "Path")
self.en_path = config_read("database", "EncryptedPath")
def tables(self):
decrypted_database = os.path.exists(self.path)
encrypted_database = os.path.exists(self.en_path)
if decrypted_database or encrypted_database:
return
con = sqlite3.connect(self.path)
self.cur = con.cursor()
tables = [self.auth_credentials, self.auth_tokens, self.profile , self.friends, self.occupations, self.occupation_requests, self.teams, self.team_leaders, self.posts, self.comments, self.post_impressions, self.comment_impressions, self.time_slots, self.notifications, self.notifications_sent]
for table in tables:
table()
def auth_credentials(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS auth_credentials (
user_id TEXT NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
password TEXT NOT NULL,
level TEXT NOT NULL,
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def auth_tokens(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS auth_tokens(
user_id TEXT NOT NULL,
token TEXT NOT NULL PRIMARY KEY,
token_expire REAL NOT NULL,
FOREIGN KEY (user_id)
REFERENCES auth_credentials (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def profile(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS profile (
user_id TEXT NOT NULL PRIMARY KEY,
occupation_id TEXT,
name TEXT,
picture TEXT,
biography TEXT,
role TEXT,
num_friends INTEGER DEFAULT 0,
FOREIGN KEY (occupation_id)
REFERENCES occupations (occupation_id)
ON UPDATE CASCADE
ON DELETE SET NULL
)
""")
def friends(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS friends (
user_id TEXT NOT NULL,
friend_id TEXT NOT NULL,
approved BOOLEAN,
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (friend_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
PRIMARY KEY (user_id, friend_id)
)
""")
def occupations(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS occupations (
occupation_id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
description TEXT
)
""")
def occupation_requests(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS occupation_requests (
user_id TEXT NOT NULL PRIMARY KEY,
occupation_id TEXT NOT NULL,
approved BOOLEAN DEFAULT False NOT NULL,
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (occupation_id)
REFERENCES occupations (occupation_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def teams(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS teams (
team_id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
occupation_id TEXT,
user_id TEXT,
FOREIGN KEY (occupation_id)
REFERENCES occupations (occupation_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def team_leaders(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS team_leaders (
user_id TEXT NOT NULL,
team_id TEXT NOT NULL,
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (team_id)
REFERENCES teams (team_id)
ON UPDATE CASCADE
ON DELETE CASCADE
PRIMARY KEY (user_id, team_id)
)
""")
def posts(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS posts (
post_id TEXT NOT NULL PRIMARY KEY,
user_id TEXT NOT NULL,
content TEXT NOT NULL,
caption TEXT,
date TEXT NOT NULL,
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def comments(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS comments (
comment_id TEXT NOT NULL PRIMARY KEY,
post_id TEXT NOT NULL,
user_id TEXT NOT NULL,
content TEXT NOT NULL,
FOREIGN KEY (post_id)
REFERENCES posts (post_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def post_impressions(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS post_impressions (
impression_id TEXT NOT NULL PRIMARY KEY,
post_id NOT NULL,
user_id NOT NULL,
type NOT NULL,
FOREIGN KEY (post_id)
REFERENCES posts (post_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def comment_impressions(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS comment_impressions (
impression_id TEXT NOT NULL PRIMARY KEY,
comment_id NOT NULL,
user_id NOT NULL,
type NOT NULL,
FOREIGN KEY (comment_id)
REFERENCES comments (comment_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
def time_slots(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS time_slots (
date TEXT NOT NULL PRIMARY KEY,
start FLOAT NOT NULL,
end FLOAT NOT NULL
)
""")
def notifications(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS notifications (
notification_id TEXT NOT NULL PRIMARY KEY,
target_id TEXT NOT NULL,
title TEXT NOT NULL,
content TEXT,
time_created FLOAT NOT NULL,
expire_after FLOAT NOT NULL
)
""")
def notifications_sent(self):
self.cur.execute("""
CREATE TABLE IF NOT EXISTS notifications_sent (
notification_id TEXT NOT NULL,
user_id TEXT NOT NULL,
time_sent FLOAT,
sent BOOLEAN DEFAULT False NOT NULL,
PRIMARY KEY (notification_id, user_id)
FOREIGN KEY (notification_id)
REFERENCES notifications (notification_id)
ON UPDATE CASCADE
ON DELETE CASCADE
FOREIGN KEY (user_id)
REFERENCES profile (user_id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
""")
class encryption():
def __init__(self, session):
self.key = key()
# needs to pass num_shares and min_shares
self.session = session
self.sss_enabled = config_read("database", "ShamirSecretSharing")
self.en_config_path = config_read("database", "EncryptionConfigPath")
self.db_path = config_read("database", "Path")
self.en_db_path = config_read("database", "EncryptedPath")
def mode(self):
# uses a large amount of logic statements to figure out what mode the server should enter on launch
# additionally what flags it should launch with
encryption_enabled = config_read("database", "Encrypt")
db_encrypted = self.key.is_db_encrypted()
mode = None
flags = []
if encryption_enabled:
if db_encrypted:
mode = "decrypt"
else:
success = self.encrypt()
if success:
mode = "decrypt"
else:
exit()
else:
if db_encrypted:
mode = "decrypt"
flags = ["forever"]
else:
mode = "normal"
self.session.db_encrypted = False
self.session.mode = mode
self.session.flags = flags
def encrypt(self, flags=[]):
if self.session.password:
password = self.session.password
else:
password = self._generate()
if not password:
log("FAIL", "Could not encrypt database, something went wrong, see logs for details")
return False
scheme = self.key.read_db_scheme(password)
with open(self.db_path, "rb") as db:
db_data = db.read()
# create new encrypted database
log("INFO", "Encrypting database")
en_db_data = scheme.encrypt(db_data)
with open(self.en_db_path, "wb") as en_db:
en_db.write(en_db_data)
# delete unecrypted database
os.remove("data/database.db")
log("INFO", "Deleted unencrypted database")
return True
def decrypt(self, data, flags=[]):
min_shares = config_read('database', 'MinimumShares')
if "sss" in flags:
password = int(shares(min_shares).get_key(data['shares']))
else:
password = int(data['password'])
scheme = self.key.read_db_scheme(password)
if not scheme:
return False
# decrypting the databsae raw bytes
with open(self.en_db_path, "rb") as en_db:
en_db_data = en_db.read()
db_data = scheme.decrypt(en_db_data)
with open(self.db_path, "wb") as db:
db.write(db_data)
if not self._database_read():
log("FAIL", "Decryption of database failed, see logs for details")
return False
log("INFO", "Decryption of database successful")
self.session.password = password
for flag in flags:
if flag == "forever":
log("WARN", "Permanent decryption of the database")
self.session.encrypt_on_shutdown = False
self.key.delete()
elif flag == "sss":
with open(self.en_config_path, "w") as en_config:
en_config.write(str(password))
log("WARN", f"You decrypted the database using Shamir secret shares, your master password has been reconstructed and can be found on the server at the location: {self.en_config_path}. Please remember to delete this file after reading")
self.session.db_encrypted = False
self.session.mode = "normal"
return True
def _generate(self):
options = self._read_config()
if not self._config_check(options):
log("FAIL", "Could not generate encryption scheme, something wrong in config file or with maseter password")
return None
else:
options['password'] = int(options['password'])
if self.sss_enabled:
options['num_shares'] = int(options['num_shares'])
options['min_shares'] = int(options['min_shares'])
self.key.generate_key_file(options['password'])
if self.sss_enabled:
log("INFO", "Shamir Secret Sharing enabled, generating shares")
sss = shares(options['min_shares'], options['num_shares'])
sss_success = sss.generate_shares(options['password'])
if not sss_success:
log("FAIL", "Something went wrong generating shamir secret shares, see log for details")
return None
log("INFO", "Deleting encryption configuration file containing master password")
os.remove(self.en_config_path)
return options['password']
def _read_config(self):
num_shares = config_read("database", "NumberOfShares")
min_shares = config_read("database", "MinimumShares")
options = {}
try:
with open(self.en_config_path, "r") as config:
log("INFO","Reading encryption configuration file")
options['password'] = config.read()
if self.sss_enabled:
options['num_shares'] = num_shares
options['min_shares'] = min_shares
except:
return None
return options
def _config_check(self, options):
# checking if the file exists
try:
en_config = open(self.en_config_path, "r")
en_config.close()
except:
log("FAIL", f"Encryption config could not be found at {self.en_config_path}")
return False
# check config contents
try:
log("INFO", "Testing master password type (must be int)")
master_pass = int(options['password'])
if len(options) == 1:
return True
elif self.sss_enabled and len(options) == 3:
log("INFO", "Testing number of shares type (must be integer)")
num_shares = int(options['num_shares'])
log("INFO", "Testing minimum shares type (must be integer)")
min_shares = int(options['min_shares'])
if num_shares < 20 and min_shares < 7:
return True
else:
log("WARN", "SSS number of shares is to large or minimum shares is to large")
return False
else:
log("WARN", "Something went wrong reading config file, check the docs for a guide")
return False
except:
log("WARN", "The master password, number of shares and minimum shares all must be integers")
return False
def _database_read(self):
try:
db = connect()
db.create(self)
db.cur.execute("SELECT * FROM time_slots")
return True
except:
return False
class key():
def __init__(self):
self.key_path = config_read("database", "KeyPath")
self.db_path = config_read("database", "Path")
self.en_db_path = config_read("database", "EncryptedPath")
self.salt_path = config_read("database", "SaltPath")
def _save_salt(self, salt):
with open(self.salt_path, "wb") as salt_file:
salt_file.write(salt)
def _read_salt(self):
try:
with open(self.salt_path, "rb") as salt_file:
salt = salt_file.read()
return salt
except:
return None
def _pass_to_scheme(self, password):
password = str(password).encode()
salt = self._read_salt()
if not salt:
salt = os.urandom(16)
self._save_salt(salt)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=480000,
)
key = base64.urlsafe_b64encode(kdf.derive(password))
scheme = Fernet(key)
return scheme
def read_db_scheme(self, password):
file_scheme = self._pass_to_scheme(password)
with open(self.key_path, "r") as key_file:
en_password = key_file.read()
db_scheme = None
try:
password = file_scheme.decrypt(en_password)
db_scheme = self._pass_to_scheme(password)
except:
log("WARN", "Provided password is wrong or something is wrong with the database key")
return db_scheme
def generate_key_file(self, password):
#db_password = bytes(uuid_generate().replace("-", "").encode())
db_password = uuid_generate().replace("-", "").encode()
file_scheme = self._pass_to_scheme(password)
en_db_password = str(file_scheme.encrypt(db_password).decode())
with open(self.key_path, "w") as key_file:
key_file.write(en_db_password)
def delete(self):
os.remove(self.salt_path)
os.remove(self.key_path)
os.remove(self.en_db_path)
def is_db_encrypted(self):
try:
db = open(self.en_db_path, "rb")
return True
except:
return False
class ShareStruct(ctypes.Structure):
__fields__ = [("y", ctypes.c_longlong), ("x", ctypes.c_int)]
# this class is mainly geared towards acting as an interface for hte c++ code
class shares():
def __init__(self, min_shares, num_shares=None):
if num_shares:
self.num_shares = int(num_shares)
self.min_shares = int(min_shares)
self.shares_path = config_read("database", "SharesPath")
def _dict_to_c_array(self, share_list):
c_share_array = ((ctypes.c_longlong*2)*self.min_shares)
share_array = []
for i in range(len(share_list)):
c_share = (ctypes.c_longlong*2)(*[share_list[i]['num'], share_list[i]['secret']])
share_array.append(c_share)
c_share_array = ((ctypes.c_longlong*2)*len(share_list))(*share_array)
return c_share_array
def generate_shares(self, password):
libname = pathlib.Path().absolute() / "modules/data/libcppsss.so"
c_lib = ctypes.CDLL(libname)
c_lib.newSecretInternal.argtypes = [ctypes.c_longlong, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_char)]
c_lib.newSecretInternal.restypes = None
path_ptr = ctypes.c_char_p(self.shares_path.encode('utf-8'))
c_lib.newSecretInternal(password, self.num_shares, self.min_shares, path_ptr)
success = self.verify(password)
return success
def get_key(self, share_list):
libname = pathlib.Path().absolute() / "modules/data/libcppsss.so"
c_lib = ctypes.CDLL(libname)
c_share_array = ((ctypes.c_longlong*2)*self.min_shares)
c_share_array_pointer = ctypes.POINTER(c_share_array)
c_lib.solveInternal.argtypes = [c_share_array_pointer, ctypes.c_int]
c_lib.solveInternal.restypes = int
new_share_array = ctypes.pointer(self._dict_to_c_array(share_list))
result = c_lib.solveInternal(new_share_array, self.min_shares)
return result
def verify(self, password):
# used to verify that the shamir secret shares generated can be used to reconstruct the original key
log("INFO", "Verifying share integrity")
# we essentially take a sample of the shares
# if all these samples work we assume any combination of said samples will
# this works well since we test the combination of all hte smallest numbers and all teh largest
# the only reason a set of shares wouldnt work is because they have become to large and c++ starts to lose accuracy
# if this doesnt happen then its safe to assume all shares work
shifts = self.num_shares - self.min_shares
for i in range(shifts):
top = i + self.min_shares
shares_used = ""
for num_share in range(i, top):
shares_used += str(num_share) + ", "
shares_used = shares_used[:-2]
log("INFO", f"Attempting to generate original password with shares: {shares_used}")
share_list = []
for j in range(i, top):
# reads the shares from their files
path = self.shares_path + f"share-{j+1}.txt"
with open(path, "r") as share:
try:
x = int((share.readline().split(": "))[1])
y = int((share.readline().split(": "))[1])
share_list.append({'num': x, 'secret': y})
except:
log("WARN", "Something went wrong reading one of the shares, have they been altered?")
break
result = self.get_key(share_list)
if result != password:
log("WARN", "A set of shares could not be used to generate the original password, try again or use a diffrent password")
return False
else:
log("INFO", f"{i+1}/{shifts} sets of shares successfully used to generate the original password")
return True
def main():
db = create()
db.path = "database.db"
db.tables()
if __name__ == "__main__":
main()
class retrieve():
def __init__(self):
self.db = db_connect()
self.db.create(self)
def level(self, identifier):
self.cur.execute("SELECT level FROM auth_credentials WHERE username = ? OR user_id = ?", (identifier, identifier))
rez = self.cur.fetchone()
if rez:
return rez[0]
def user_id(self, username):
self.cur.execute("SELECT user_id FROM auth_credentials WHERE username = ?", (username,))
rez = self.cur.fetchone()
if rez:
rez = rez[0]
return rez
def username(self, user_id):
self.cur.execute("SELECT username FROM auth_credentials WHERE user_id = ?", (user_id,))
rez = self.cur.fetchone()
if rez:
rez = rez[0]
return rez
def occupation_id(self, user_id):
self.cur.execute("SELECT occupation_id FROM profile WHERE user_id = ?", (user_id,))
rez = self.cur.fetchone()
if rez:
rez = rez[0]
return rez

View File

@@ -0,0 +1,125 @@
from datetime import date, timedelta, datetime
import random
import eventlet
# MODULES
from modules.data.config import read as config_read
from modules.data.database import connect as db_connect
from modules.handler import outgoing
from modules.track.logging import log
# MODULES
class timestamp():
def __init__(self):
self.time_limit = float(config_read("posts", "PostTimeLimit")) * 60
self.db = db_connect()
self.db.create(self)
@property
def start(self):
value = self.get_date_timestamp()
self._start = value
return self._start
@start.setter
def start(self, value):
value = self.get_date_timestamp()
self._start = value
@property
def end(self):
value = self.get_date_timestamp(day_mod=1) - 1
self._end = value
return self._end
@end.setter
def end(self, value):
value = self.get_date_timestamp(day_mod=1) - 1
self._end = value
@property
def now(self):
value = self.get_timestamp()
self._now = value
return value
@now.setter
def now(self, value):
value = self.get_timestamp()
self._now = value
@property
def post_slot_start(self):
value = self.get_slot()['start']
self._post_slot_start = value
return self._post_slot_start
@post_slot_start.setter
def post_slot_start(self, value):
self._post_slot_start = self._post_slot_start
@property
def post_slot_end(self):
value = self.get_slot()['end']
self._post_slot_end = value
return self._post_slot_end
@post_slot_end.setter
def post_slot_end(self, value):
self._post_slot_end = self._post_slot_end
@property
def date(self):
date = str(datetime.now().date())
self._date = date
return self._date
@date.setter
def date(self, value):
self._date = value
def get_date_timestamp(self, year_mod=0, month_mod=0, day_mod=0, *args, **kwargs):
modifier = [year_mod, month_mod, day_mod]
now_mod = (datetime.now()+timedelta(days=day_mod))
date = (str(now_mod.date()).replace("-0", "-")).split("-")
date = [int(string) for string in date]
timestamp = datetime(date[0], date[1], date[2]).timestamp()
return timestamp
def get_timestamp(self):
now = (float(datetime.now().timestamp()))
return now
def generate_slot(self, data=None):
for i in range(2):
if i == 0:
date = str(datetime.now().date())
start = self.get_date_timestamp()
else:
now_mod = (datetime.now()+timedelta(days=1))
date = (str(now_mod.date()))
start = self.get_date_timestamp(0, 0, 1)
self.cur.execute("SELECT date FROM time_slots WHERE date=?", (date,))
if not self.cur.fetchone():
log("INFO", f"Generating time slot for {date}")
day_start = start + int(config_read("posts", "DayStart")) * 60 * 60
day_end = start + int(config_read("posts", "DayStart")) * 60 * 60
slot_start = random.randint(day_start, day_end)
slot_end = slot_start + self.time_limit
self.cur.execute("INSERT INTO time_slots (date, start, end) VALUES (?, ?, ?)", (date, slot_start, slot_end))
self.db.commit()
def get_slot(self):
info = None
date = str(datetime.now().date())
self.cur.execute("SELECT start, end FROM time_slots WHERE date=?", (date,))
rez = self.cur.fetchone()
if rez:
info = {'start':rez[0], 'end':rez[1]}
return info
def is_valid_time(self):
if (self.now < self.post_slot_end) and (self.now >= self.post_slot_start):
return True
return False

Binary file not shown.

390
server/modules/data/sss.cpp Normal file
View File

@@ -0,0 +1,390 @@
#include <cstdlib>
# include<iostream>
# include<string>
# include<random>
# include<cmath>
# include<array>
#include <fstream>
using namespace std;
typedef long long int Lint; // 64 bits
typedef double Ldouble;
struct security {
int num_shares;
int num_required;
};
struct shareStruct {
int x;
Lint y;
};
bool isPrime(Lint n) {
int flag = 0;
for (int i = 2; i <= n / i; ++i) {
if (n % i == 0) {
flag = 1;
break;
}
}
if (flag == 0) return true;
else return false;
}
Lint genRandInt(int n) {
// Returns a random number
// between 2**(n-1)+1 and 2**n-1
//long max = (long)powl(2, n) - 1;
//long min = (long)powl(2, n - 1) + 1;
long max = (long)pow(2, n) - 1;
long min = (long)pow(2, n - 1) + 1;
Lint result = min + (rand() % ( max - min + 1 ) );
return result;
}
Lint genPrime() {
Lint prime = 10;
while (isPrime(prime) == false) {
int complexity = 50;
prime = genRandInt(complexity);
}
return prime;
}
int* encodeSecret(int* poly, const int secret, const int num_required) {
poly[num_required-1] = secret;
return poly;
}
Lint getPolyY(const int* poly, int poly_len, int poly_x, const Lint prime) {
Lint total = 0;
Lint poly_y = 0;
for (int i=0; i<poly_len+1; i++) {
int power = poly_len - i;
int coefficient = poly[i];
poly_y = coefficient * pow(poly_x, power);
total = total + poly_y;
}
return total;
}
shareStruct* genShares(int num_shares, int num_required, const int* poly, const Lint prime){
shareStruct* shares = new shareStruct[num_shares];
for (int i=1; i<=num_shares; i++) {
shareStruct share;
share.x = i;
share.y = getPolyY(poly, num_required-1, share.x, prime);
shares[i-1] = share;
}
return shares;
}
int* genPoly(int degree, const Lint prime, const Lint secret) {
int* poly = new int[degree];
for (int i = 0; i < degree; i++) {
int random_num = genRandInt(10);
poly[i] = prime % random_num;
}
return poly;
}
// solving polynomials
struct inputStruct {
int required;
shareStruct* shares;
};
struct polyTerm {
Lint coefficient;
int power;
};
struct linearEquation {
shareStruct point;
polyTerm* terms;
};
linearEquation* constructEquations(const int required, shareStruct shares[]) {
linearEquation* equations = new linearEquation[required];
shareStruct share;
polyTerm term;
for (int i = 0; i < required; i++) {
share = shares[i];
linearEquation equation;
polyTerm* terms = new polyTerm[required];
for (int j = 0; j < required; j++) {
term.power = required - 1 - j;
terms[j] = term;
}
equation.terms = terms;
equation.point.x = share.x;
equation.point.y = share.y;
equations[i] = equation;
// dont delete terms from memory as its referanced in equations
}
return equations;
}
struct matrix{
Lint** matrix;
int dimension_x;
int dimension_y;
};
struct matrix_system {
matrix A;
matrix B;
matrix X;
};
matrix_system formMatrix(const linearEquation* equations, int required) {
Lint** matrixA = new Lint*[required];
Lint** matrixB = new Lint*[required];
for (int i=0; i < required; i++) {
linearEquation equation = equations[i];
Lint* lineA = new Lint[required];
for (int j=0; j < required; j++) {
lineA[j] = pow(equation.point.x, equation.terms[j].power);
}
matrixA[i] = lineA;
Lint* lineB = new Lint[1];
lineB[0] = equation.point.y;
matrixB[i] = lineB;
}
matrix matrixA_data; matrix matrixB_data;
matrixA_data.matrix = matrixA; matrixB_data.matrix = matrixB;
matrixA_data.dimension_x = required; matrixB_data.dimension_x = 1;
matrixA_data.dimension_y = required; matrixB_data.dimension_y = required;
matrix_system matricies;
matricies.A = matrixA_data; matricies.B = matrixB_data;
return matricies;
}
Lint** findMinor(Lint** matrixA, const int dimension, const int pos_x, const int pos_y) {
Lint** matrixB = new Lint*[dimension-1];
int matrixB_pos_x = 0; int matrixB_pos_y = 0;
for (int i=0; i<dimension; i++) {
Lint* line = new Lint[dimension-1];
for (int j=0; j<dimension; j++) {
if (i != pos_y and j != pos_x) {
line[matrixB_pos_x] = matrixA[i][j];
matrixB_pos_x++;
}
}
if (matrixB_pos_x != 0) {
matrixB[matrixB_pos_y] = line;
matrixB_pos_y++;
}
else {
delete[] line;
}
matrixB_pos_x = 0;
}
return matrixB;
}
Lint findDet(Lint** matrixA, const int dimension) {
Lint det = 0;
if (dimension == 0) {
det = 1;
}
else if (dimension == 1) {
det = matrixA[0][0];
}
else if (dimension == 2) {
det = matrixA[0][0] * matrixA[1][1] - matrixA[0][1] * matrixA[1][0];
}
else {
for (int i=0; i<dimension; i++) {
// reuse form matrix? pottentially split it up into formMatrixA and formMatrixB?
Lint** matrixB = findMinor(matrixA, dimension, i, 0);
Lint matrixB_det = findDet(matrixB, dimension-1);
Lint term = matrixA[0][i] * matrixB_det;
if ((i+1)%2 == 0) {
term = 0-term;
}
det = det + term;
}
}
return det;
}
matrix formMatrixCofactors(Lint** matrixA, const int dimension) {
Lint** matrixB = new Lint*[dimension];
for (int i=0; i<dimension; i++) {
Lint* line = new Lint[dimension];
int sign = 1;
if ((i+1)%2 == 0) {
sign = -1;
}
for (int j=0; j<dimension; j++) {
Lint** minor = findMinor(matrixA, dimension, j, i);
Lint cofactor = findDet(minor, dimension-1) * sign;
sign = -sign;
line[j] = cofactor;
}
matrixB[i] = line;
}
matrix matrix_data; matrix_data.matrix = matrixB;
matrix_data.dimension_x = dimension; matrix_data.dimension_y = dimension;
return matrix_data;
}
matrix transposeMatrix(Lint** cofactors, const int dimension) {
Lint** matrixB = new Lint*[dimension];
for (int i=0; i<dimension; i++) {
Lint* line = new Lint[dimension];
for (int j=0; j<dimension; j++) {
line[j] = cofactors[j][i];
}
matrixB[i] = line;
}
matrix matrixB_data; matrixB_data.matrix = matrixB;
matrixB_data.dimension_x = dimension; matrixB_data.dimension_y = dimension;
return matrixB_data;
}
struct float_matrix{
Ldouble** matrix;
int dimension_x;
int dimension_y;
};
struct float_matrix_system {
matrix A;
matrix B;
matrix X;
};
float_matrix multiplyConstant(matrix matrixA_data, const int dimension, const Lint det) {
Ldouble** matrixB = new Ldouble*[dimension];
Lint** matrixA = matrixA_data.matrix;
for (int i=0; i<dimension; i++) {
Ldouble* line = new Ldouble[dimension];
for (int j=0; j<dimension; j++) {
line[j] = (1.0/det) * matrixA[i][j];
}
matrixB[i] = line;
}
float_matrix matrixB_data; matrixB_data.matrix = matrixB;
matrixB_data.dimension_x = matrixA_data.dimension_x; matrixB_data.dimension_y = matrixA_data.dimension_y;
return matrixB_data;
}
float_matrix multiplyMatricies(float_matrix inverseA_data, matrix matrixB_data) {
int dimension_x = inverseA_data.dimension_x;
int dimension_y = inverseA_data.dimension_y;
Ldouble** matrixC = new Ldouble*[matrixB_data.dimension_y];
Ldouble** inverseA = inverseA_data.matrix;
Lint** matrixB = matrixB_data.matrix;
for (int i=0; i<dimension_y; i++) {
Ldouble* line = new Ldouble[0];
Ldouble result = 0;
for (int j=0; j<dimension_x; j++) {
result = result + inverseA[i][j] * matrixB[j][0];
}
line[0] = result;
matrixC[i] = line;
}
float_matrix matrixC_data; matrixC_data.matrix = matrixC;
matrixC_data.dimension_x = matrixB_data.dimension_x; matrixC_data.dimension_y = matrixB_data.dimension_y;
return matrixC_data;
}
Lint** StructToArray(shareStruct* struct_array, int len_array) {
Lint** array = new Lint*[len_array];
for (int i=0; i<len_array; i++) {
array[i] = new Lint[2];
array[i][0] = struct_array[i].x;
array[i][1] = struct_array[i].y;
}
return array;
}
shareStruct* ArrayToStruct(Lint** array, int len_array) {
shareStruct* share_array = new shareStruct[len_array];
for (int i=0; i<len_array; i++) {
shareStruct share;
share.x = array[i][0];
share.y = array[i][1];
share_array[i] = share;
}
return share_array;
}
void writeShares(shareStruct* shares, const int num_shares, const int num_required, string root_path) {
cout << root_path << endl;
for (int i=0; i<num_shares; i++) {
shareStruct share = shares[i];
string share_path = root_path + "share-" + to_string(share.x) + ".txt";
ofstream share_file(share_path);
share_file << "Share number: " << share.x << endl;
share_file << "Share secret: " << share.y << endl;
share_file << "Minimum share required: " << to_string(num_required) << endl << endl;
share_file << "IMPORTANT: Please remind your admin that its there job to distribute and delete shares from the server";
}
}
extern "C" Lint solveInternal(shareStruct* shares, int required) {
inputStruct inputs;
inputs.shares = shares;
inputs.required = required;
linearEquation* equations = new linearEquation[inputs.required];
equations = constructEquations(inputs.required, inputs.shares);
matrix_system matricies = formMatrix(equations, inputs.required);
delete[] equations;
Lint det = findDet(matricies.A.matrix, matricies.A.dimension_x);
matrix cofactors = formMatrixCofactors(matricies.A.matrix, matricies.A.dimension_x);
matrix transposition = transposeMatrix(cofactors.matrix, cofactors.dimension_x);
float_matrix inverseA = multiplyConstant(transposition, transposition.dimension_x, det);
float_matrix matrixC = multiplyMatricies(inverseA, matricies.B);
Lint secret = matrixC.matrix[matrixC.dimension_y-1][0];
return secret;
}
extern "C" void newSecretInternal(const Lint secret, const int num_shares, const int num_required, char* root_path) {
string str(root_path);
const Lint prime = genPrime();
int* poly = genPoly(num_required-1, prime, secret);
poly = encodeSecret(poly, secret, num_required);
shareStruct* shares = genShares(num_shares, num_required, poly, prime);
writeShares(shares, num_shares, num_required, root_path);
}
int main() {
}