-
Notifications
You must be signed in to change notification settings - Fork 0
/
db-functions.js
183 lines (160 loc) · 4.45 KB
/
db-functions.js
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
const crypto = require('crypto')
const { MongoClient } = require('mongodb')
const { mongoDBURI, mongoDBName, mongoDBUserCollection } = require('./config.json')
const client = new MongoClient(mongoDBURI)
module.exports.client = client
class GameData {
constructor() {
/** @type {number} */
this.played = 0
/** @type {number} */
this.wins = 0
/** @type {number} */
this.streak = 0
/** @type {number} */
this.maxStreak = 0
/** @type {number[]} */
this.results = [0, 0, 0, 0, 0, 0]
/** @type {number} */
this.lastPlayed = 0
/** @type {number} */
this.lastWon = 0
/** @type {string} */
this.secret = ''
/** @type {string[]} */
this.tries = []
}
}
module.exports.GameData = GameData
class UserData {
/**
* @param {string} email
* @param {password} password
* @returns {UserData}
*/
constructor(email, password) {
/** @type {string} */
this.email = email
/**
* Secret key created randomly used to encrypt the password so
* its not saved in clear in the server
* @type {string}
*/
this.secretKey = crypto.randomBytes(24).toString('base64')
/**
* User password hashed ready to be stored
* @type {string}
*/
this.encPassword = crypto.createHmac('sha256', this.secretKey).update(password).digest('base64')
/**
* Coookie to be used when the used correctly logs in. The cookie is created
* by hashing the email with a secret key generated randomly (different from
* the one used for the password)
* @type {string}
*/
this.cookieValue = generateNewCookie(email)
/**
* Data holds the game statistics organized in a Map:
* + the keys of the map are strings and rapresent the language of the game (es: it, en)
* + the values of the map are the statistics that has the same structure of GameData
* @type {Map<string, GameData>}
*/
this.data = new Map()
}
json() {
return JSON.stringify(this)
}
}
module.exports.UserData = UserData
/**
* @param {string} email
* @returns {string} CookieValue
*/
function generateNewCookie(email) {
return crypto.createHmac(
'sha256',
crypto.randomBytes(24).toString('base64')
).update(email).digest('base64')
}
/**
* @param {string} email
* @returns {Promise<boolean>} Exists
*/
async function checkUser(cookieValue) {
let db = client.db(mongoDBName).collection(mongoDBUserCollection)
let res = await db.findOne({ cookieValue: cookieValue })
if (!res) {
return false
}
return true
}
module.exports.checkUser = checkUser
/**
* @param {string} email
* @param {string} password
* @returns {Promise<string | null>} Ok
*/
async function registerUser(email, password) {
let db = client.db(mongoDBName).collection(mongoDBUserCollection)
if (await db.findOne({ email: email })) {
throw new Error('User already registered')
}
let user = new UserData(email, password);
let res = await db.insertOne(user)
if (!res.acknowledged) {
return null
}
return user.cookieValue
}
module.exports.registerUser = registerUser
/**
* @param {string} email
* @param {string} password
* @returns {Promise<string | null>} Cookie value
*/
async function loginUser(email, password) {
let db = client.db(mongoDBName).collection(mongoDBUserCollection)
/** @type {UserData} */
let user = await db.findOne({ email: email })
if (!user) {
return null
}
if (crypto.createHmac('sha256', user.secretKey).update(password).digest('base64') !== user.encPassword) {
return null
}
let newCookieValue = generateNewCookie(email)
let res = await db.updateOne({ email: email }, { $set: { cookieValue: newCookieValue } })
if (!res.acknowledged) {
return null
}
return newCookieValue
}
module.exports.loginUser = loginUser
/**
* @param {string} cookieValue
* @returns {Promise<Map<string, GameData>>} User data
*/
async function getUserData(cookieValue) {
let db = client.db(mongoDBName).collection(mongoDBUserCollection)
let user = await db.findOne({ cookieValue: cookieValue })
if (!user) {
throw new Error('Could not find user')
}
let data = new Map()
for (let key in user.data) {
data.set(key, user.data[key])
}
return data
}
module.exports.getUserData = getUserData
/**
* @param {string} cookieValue
* @param {Map<string, GameData>} newData
* @returns {Promise<boolean>} Ok
*/
async function updateUserData(cookieValue, newData) {
let db = client.db(mongoDBName).collection(mongoDBUserCollection)
let res = await db.updateOne({ cookieValue: cookieValue }, { $set: { data: newData } })
return res.acknowledged
}
module.exports.updateUserData = updateUserData