Saving token used and time joined

This commit is contained in:
metacryst
2025-11-24 00:56:15 -06:00
parent 40e7987ca2
commit 6299e80268
7 changed files with 81 additions and 62 deletions

View File

@@ -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");
}
}

View File

@@ -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}`;
}
}

View File

@@ -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]

View File

@@ -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)) {

View File

@@ -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
}
}

View File

@@ -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' });
}
}