diff --git a/db/db.json b/db/db.json index 5526cb9..61aba61 100644 --- a/db/db.json +++ b/db/db.json @@ -7,20 +7,22 @@ "email": "samrussell99@pm.me", "firstName": "Sam", "lastName": "Russell", - "password": "$argon2id$v=19$m=65536,t=3,p=4$LEd8Zx9YXccDMQyyBYp1oA$+zNo5x6BRRhCcsKvX2zcEAvdth/+tqwN1uqZ8Di/71w", + "password": "$argon2id$v=19$m=65536,t=3,p=4$PDu5qx47zzY0dX0/4iQuqw$JxePLouwOEi2Q0wA4JHQQ4GwvqAvxqWhj7n9aC8HZIk", "address": { "address1": "2014 E 9th St", "address2": "Unit A", "zip": "78702", "state": "Texas", "city": "Austin" - } + }, + "tokenUsed": "810387b6-851e-4883-b9a3-c59703dc0fc9", + "joined": "11.24.2025-12:54:360784am" }, "TOKEN-810387b6-851e-4883-b9a3-c59703dc0fc9": { "index": 1, "url": "https://hyperia.so/signup?token=", "uuid": "810387b6-851e-4883-b9a3-c59703dc0fc9", - "used": false + "used": true }, "TOKEN-d0b417c4-d69a-4958-9e1d-0658176d2710": { "index": 2, diff --git a/server/db/db.js b/server/db/db.js index f825cbe..00798ed 100644 --- a/server/db/db.js +++ b/server/db/db.js @@ -39,7 +39,7 @@ export default class Database { try { let collection = this.fromID[type] if(collection) { - collection.add(node) + collection.save(node) } else { throw new Error("Type does not exist for node: ", id) } @@ -77,6 +77,7 @@ export default class Database { } } - await fs.writeFile(path.join(process.cwd(), 'db/db.json'), JSON.stringify(data, null, 4), "utf8"); + let string = JSON.stringify(data, null, 4) + await fs.writeFile(path.join(process.cwd(), 'db/db.json'), string, "utf8"); } } \ No newline at end of file diff --git a/server/db/model/Members.js b/server/db/model/Members.js index ca8d1b6..404dad0 100644 --- a/server/db/model/Members.js +++ b/server/db/model/Members.js @@ -13,34 +13,61 @@ export default class Members extends OrderedObject { schema = z.object({ email: z.string().email(), firstName: z.string(), - lastName: z.number().int().min(0), + lastName: z.string(), password: z.string(), - address: this.addressSchema + tokenUsed: z.string().regex( + /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, + "Invalid UUID" + ), + joined: z.string(), + address: this.addressSchema, }) isHashed = (s) => {return s.startsWith("$argon2")} - async add(newMember) { - console.log("adding ", newMember) - let id = `MEMBER-${newMember.email}` - if(this.schema.safeParse(newMember)) { - if(!this.isHashed(newMember.password)) { - const hash = await argon2.hash(newMember.password); - newMember.password = hash - } + save(member) { + let id = `MEMBER-${member.email}` + let result = this.schema.safeParse(member) + if(result.success) { try { - super.add(id, newMember) + super.add(id, member) } catch(e) { console.error(e) throw e } } else { - throw new global.ServerError(400, "Invalid Member Data!"); + console.error("Failed parsing member: ", result.error) + throw new global.ServerError(400, "Invalid Member Data!: "); } - global.db.saveData() + } + + async add(newMember, tokenID) { + newMember.tokenUsed = tokenID + const hash = await argon2.hash(newMember.password); + newMember.password = hash + newMember.joined = this.currentTime() + this.save(newMember) } getByEmail(email) { return super.get(`MEMBER-${email}`) } + + currentTime() { + const now = new Date(); + + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); + const year = now.getFullYear(); + + let hours = now.getHours(); + const ampm = hours >= 12 ? "pm" : "am"; + hours = hours % 12 || 12; // convert to 12-hour format + + const minutes = String(now.getMinutes()).padStart(2, "0"); + const seconds = String(now.getSeconds()).padStart(2, "0"); + const ms = String(now.getMilliseconds()).padStart(4, "0"); // 4-digit like "5838" + + return `${month}.${day}.${year}-${hours}:${minutes}:${seconds}${ms}${ampm}`; + } } \ No newline at end of file diff --git a/server/db/model/OrderedObject.js b/server/db/model/OrderedObject.js index 5d91869..09d884d 100644 --- a/server/db/model/OrderedObject.js +++ b/server/db/model/OrderedObject.js @@ -11,6 +11,11 @@ export default class OrderedObject { this.ids[id] = this.entries.length - 1 } + update(id, data) { + let index = this.ids[id] + this.entries[index] = data + } + delete(key) { if (typeof key === "number") { return this.entries[key] diff --git a/server/db/model/Titles.js b/server/db/model/Titles.js index 5e37cfc..adf418b 100644 --- a/server/db/model/Titles.js +++ b/server/db/model/Titles.js @@ -2,7 +2,7 @@ import OrderedObject from "./OrderedObject.js" export default class Titles extends OrderedObject { - add(newTitle) { + save(newTitle) { let id = `HY-${this.entries.length+1}` console.log(id) if(this.validate(id, newTitle)) { diff --git a/server/db/model/Tokens.js b/server/db/model/Tokens.js index 8d74b5d..7a181c2 100644 --- a/server/db/model/Tokens.js +++ b/server/db/model/Tokens.js @@ -1,10 +1,28 @@ import OrderedObject from "./OrderedObject.js" +const { z } = require("zod") export default class Tokens extends OrderedObject { - add(token) { + schema = z.object({ + index: z.number(), + url: z.string(), + uuid: z.string().regex( + /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, + "Invalid UUID" + ), + used: z.boolean(), + }) + + markUsed(uuid) { + let token = this.get(uuid) + token.used = true + super.update(`TOKEN-${uuid}`, token) + } + + save(token) { let id = `TOKEN-${token.uuid}` - if(this.validate(id, token)) { + let result = this.schema.safeParse(token) + if(result.success) { try { super.add(id, token) } catch(e) { @@ -12,6 +30,7 @@ export default class Tokens extends OrderedObject { throw e } } else { + console.error(result.error) throw new global.ServerError(400, "Invalid Member Data!"); } } @@ -19,44 +38,4 @@ export default class Tokens extends OrderedObject { get(uuid) { return super.get(`TOKEN-${uuid}`) } - - validate(id, node) { - let idTraits = { - firstWord: "TOKEN" - } - - let fields = [ - "index", - "url", - "used" - ] - - let checkID = () => { - let split = id.split("-") - return ( - split[0] === idTraits.firstWord - ) - } - let idres = checkID() - if(!idres) { - return false - } - - let checkFields = () => { - for(let i = 0; i < fields.length; i++) { - if(!node[fields[i]]) { - throw new Error(`Token ${node.email} is missing trait ${fields[i]}`) - return false - } else { - return true - } - } - } - let fieldres = checkFields() - if(!fieldres) { - return false - } - - return true - } } \ No newline at end of file diff --git a/server/index.js b/server/index.js index 6f620af..b351f1d 100644 --- a/server/index.js +++ b/server/index.js @@ -46,9 +46,14 @@ class Server { newUserSubmission = async (req, res) => { const { token } = req.query; try { - await db.members.add(req.body) + let tokenData = db.tokens.get(token) + if(tokenData.used) throw new global.ServerError(400, "Token alredy used!") + await db.members.add(req.body, tokenData.uuid) + db.tokens.markUsed(token) + global.db.saveData() return res.status(200).json({}); } catch(e) { + console.log(e) return res.status(e.status).json({ error: 'Error adding new member' }); } }