-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathuser.py
More file actions
193 lines (167 loc) · 6.02 KB
/
user.py
File metadata and controls
193 lines (167 loc) · 6.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import json, random, os, hashlib
from datetime import datetime, timedelta
from config import EXTENDED_ALPHABET
def rand_short():
return "".join([random.choice(EXTENDED_ALPHABET) for _ in range(10)])
def rand_long():
return "".join([random.choice(EXTENDED_ALPHABET) for _ in range(32)])
class Users:
email_to_id = {}
username_to_id = {}
@staticmethod
def save_indexing():
with open("users/indexing.json",'w') as f:
json.dump({
"email": Users.email_to_id,
"username": Users.username_to_id
},f)
print({
"email": Users.email_to_id,
"username": Users.username_to_id
})
@staticmethod
def load_indexing():
if not os.path.exists("users/indexing.json"): Users.save_indexing()
with open("users/indexing.json") as f:
a = json.load(f)
Users.email_to_id = a["email"]
Users.username_to_id = a["username"]
@staticmethod
def del_empty():
paths = os.listdir("users/")
for path in paths:
if path == "indexing.json" or path == "readme.md": continue
try: user = User(path[:-5])
except:
os.remove("users/" + path)
continue
if user.hashed_pass == "": os.remove("users/" + path)
@staticmethod
def exists(id:str) -> bool:
return os.path.exists(f"users/{id}.json")
class User:
def __init__(self, id=""):
if id!="":
self.id=id
self.load()
return
self.id = rand_short()
self.username = ""
self.email = ""
self.hashed_pass = ""
self.salt = ""
self.solved_problems:dict[str, str] = {}
self.attempted_problems:dict[str,str] = {}
self.joined_contests = []
self.date_created = datetime.now().strftime("%m-%d-%Y-%H-%M-%S")
self.admin = False
self.tokens = []
self.save()
def to_json(self) -> dict:
jsoned = {
"id": self.id,
"username": self.username,
"email": self.email,
"admin": self.admin,
"login": {
"password": self.hashed_pass,
"salt": self.salt
},
"problems": {
"attempted": self.attempted_problems,
"solved": self.solved_problems
},
"contests": { "joined": self.joined_contests },
"meta": { "date-created": self.date_created },
"tokens": self.tokens
}
return jsoned
def from_json(self, jsoned):
self.id = jsoned["id"]
self.username = jsoned["username"]
self.email = jsoned["email"]
self.admin = jsoned["admin"]
self.hashed_pass = jsoned["login"]["password"]
self.salt = jsoned["login"]["salt"]
self.attempted_problems = jsoned["problems"]["attempted"]
self.solved_problems = jsoned["problems"]["solved"]
self.joined_contests = jsoned["contests"]["joined"]
self.date_created = jsoned["meta"]["date-created"]
self.tokens = []
if "tokens" in jsoned: self.tokens=jsoned["tokens"]
def load(self):
if not os.path.exists(f"users/{self.id}.json"): raise FileNotFoundError
with open(f"users/{self.id}.json") as f:
self.from_json(json.load(f))
def save(self):
with open(f"users/{self.id}.json",'w') as f:
json.dump(self.to_json(),f)
def set_details(self, username, email):
self.load()
self.username = username
self.email = email
Users.load_indexing()
Users.username_to_id[self.username] = self.id
Users.email_to_id[self.email] = self.id
Users.save_indexing()
self.save()
def set_hash_pass(self, hashed_pass):
self.hashed_pass = hashed_pass
self.save()
def set_salt(self) -> str:
self.load()
if self.salt != "" and self.hashed_pass != "": return self.salt
self.salt = rand_long()
self.save()
return self.salt
def add_attempted(self, problem, id):
self.load()
self.attempted_problems[problem] = id
self.save()
def add_solved(self, problem, id):
self.load()
self.solved_problems[problem] = id
self.save()
def check_pass(self, hashedpass):
'''
Checks the login against `hashedpass` which SHOULD be hash(hash(pass)+[MM/YYYY]) --> auto expires at end of month
'''
def hash(text:str) -> str:
encoded = text.encode()
return hashlib.sha256(encoded).hexdigest()
date = datetime.now().strftime("%m-%Y")
if self.hashed_pass == "" or self.salt=="": return False
if hashedpass == hash(self.hashed_pass + date): return True
return False
# this token system is horrendus but... it's *my* horrendus token system :)
def remove_expired_tokens(self):
self.load()
i=len(self.tokens)-1
removed=False
ONE_MONTH = timedelta(days=31)
TODAY = datetime.now()
while i>=0:
token = self.tokens[i]
date = datetime(int(token["date"][1]),int(token["date"][0]),1)
if date + ONE_MONTH < TODAY:
print(f"Removing token for {date} bc today is {TODAY}")
self.tokens.pop(i)
removed=True
i-=1
if removed: self.save()
def generate_token(self) -> str:
self.load()
token = rand_long()
month = datetime.now().month
year = datetime.now().year
TODAY = [month, year]
self.tokens.append({"date":TODAY,"value":token})
self.save()
return token
def check_token(self, token) -> bool:
self.remove_expired_tokens()
for t in self.tokens:
if token == t["value"]: return True
return False
def __str__(self)->str:
return f"<User id: {self.id}, username: {self.username} {'admin' if self.admin else ''}>"