-
Notifications
You must be signed in to change notification settings - Fork 569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#648 invalid race post request #723
base: main
Are you sure you want to change the base?
Changes from all commits
5406fef
ae7f22f
9da08c3
ed60da7
708bccc
f15374a
1d70142
3c96b45
e46bad7
e2bd5f4
597292f
ade22ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,49 @@ import { UnauthorizedError } from "@/lib/exceptions/custom-hooks"; | |
import { prisma } from "@/lib/prisma"; | ||
import { getCurrentUser } from "@/lib/session"; | ||
import { validatedCallback } from "@/lib/validatedCallback"; | ||
import CryptoJS from "crypto-js"; | ||
|
||
export const getUserTokenAndStamp = async () => { | ||
const user = await getCurrentUser(); | ||
|
||
if (!user) | ||
return { | ||
key: "deFau1tk3y", | ||
stamp: "11011011", | ||
}; | ||
|
||
const userData = await prisma.user.findUnique({ | ||
where: { id: user.id }, | ||
}); | ||
|
||
if (!userData) return; | ||
|
||
let signToken = userData.signToken; | ||
let stamp = userData.stamp; | ||
|
||
if (userData!.signTokenValidity.getTime() < Date.now()) { | ||
stamp = Math.random().toString(36).substring(2, 7); | ||
signToken = Math.random().toString(36).substring(2, 22); | ||
|
||
await prisma.$transaction(async (tx) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need transaction in here?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is needed for data migration part. To introduce new token field into database. As well as to update token every 7 days to strengthen the security |
||
await tx.user.update({ | ||
where: { | ||
id: user.id, | ||
}, | ||
data: { | ||
stamp: stamp, | ||
signToken: signToken, | ||
signTokenValidity: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7), | ||
}, | ||
}); | ||
}); | ||
} | ||
|
||
return { | ||
key: signToken, | ||
stamp: stamp, | ||
}; | ||
}; | ||
|
||
export const saveUserResultAction = validatedCallback({ | ||
inputValidation: z.object({ | ||
|
@@ -15,11 +58,47 @@ export const saveUserResultAction = validatedCallback({ | |
cpm: z.number(), | ||
accuracy: z.number().min(0).max(100), | ||
snippetId: z.string(), | ||
hash: z.string(), | ||
}), | ||
callback: async (input) => { | ||
const user = await getCurrentUser(); | ||
|
||
if (!user) throw new UnauthorizedError(); | ||
if (!user) { | ||
// verify hash: | ||
const tokenAndStamp = await getUserTokenAndStamp(); | ||
const data = { | ||
timeTaken: input.timeTaken, | ||
errors: input.errors, | ||
cpm: input.cpm, | ||
accuracy: input.accuracy, | ||
snippetId: input.snippetId, | ||
stamp: tokenAndStamp!["stamp"], | ||
}; | ||
const jsonData = JSON.stringify(data); | ||
const hashedData = CryptoJS.HmacSHA256( | ||
jsonData, | ||
tokenAndStamp!["key"] | ||
).toString(); | ||
|
||
if (hashedData != input.hash.toString()) { | ||
return "Invalid Request: Tampered Data"; | ||
} else { | ||
return { | ||
takenTime: input.timeTaken.toString(), | ||
errorCount: input.errors, | ||
cpm: input.cpm, | ||
accuracy: new Prisma.Decimal(input.accuracy), | ||
snippetId: input.snippetId, | ||
RaceParticipant: input.raceParticipantId | ||
? { | ||
connect: { | ||
id: input.raceParticipantId, | ||
}, | ||
} | ||
: undefined, | ||
}; | ||
} | ||
} | ||
|
||
const userData = await prisma.user.findUnique({ | ||
where: { id: user.id }, | ||
|
@@ -64,6 +143,28 @@ export const saveUserResultAction = validatedCallback({ | |
.sort((a, b) => languagesMap[b] - languagesMap[a]) | ||
.splice(0, 3); | ||
|
||
// verify hash: | ||
const tokenAndStamp = await getUserTokenAndStamp(); | ||
const data = { | ||
timeTaken: input.timeTaken, | ||
errors: input.errors, | ||
cpm: input.cpm, | ||
accuracy: input.accuracy, | ||
snippetId: input.snippetId, | ||
stamp: tokenAndStamp!["stamp"], | ||
}; | ||
const jsonData = JSON.stringify(data); | ||
const hashedData = CryptoJS.HmacSHA256( | ||
jsonData, | ||
tokenAndStamp!["key"] | ||
).toString(); | ||
|
||
const stamp = Math.random().toString(36).substring(2, 7); | ||
|
||
if (hashedData != input.hash.toString()) { | ||
return "Invalid Request: Tampered Data"; | ||
} | ||
|
||
return await prisma.$transaction(async (tx) => { | ||
const result = await tx.result.create({ | ||
data: { | ||
|
@@ -102,6 +203,7 @@ export const saveUserResultAction = validatedCallback({ | |
averageCpm: avgValues._avg.cpm ?? 0, | ||
languagesMap: JSON.stringify(languagesMap), | ||
topLanguages: topLanguages, | ||
stamp: stamp, | ||
}, | ||
}); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ const page = () => { | |
<h1>CodeRacer - Terms of Service</h1> | ||
<p><strong>Effective Date:</strong> [Date]</p> | ||
|
||
<p>Welcome to CodeRacer! These Terms of Service ("Terms") constitute a legal agreement between you and CodeRacer. Please read these Terms carefully before using our platform, which is accessible at <a href="https://code-racer-eight.vercel.app/">https://code-racer-eight.vercel.app/</a>. By using CodeRacer, you agree to be bound by these Terms.</p> | ||
<p>Welcome to CodeRacer! These Terms of Service ({`"Terms"`}) constitute a legal agreement between you and CodeRacer. Please read these Terms carefully before using our platform, which is accessible at <a href="https://code-racer-eight.vercel.app/">https://code-racer-eight.vercel.app/</a>. By using CodeRacer, you agree to be bound by these Terms.</p> | ||
|
||
<h2>1. User Accounts</h2> | ||
<p> | ||
|
@@ -45,7 +45,7 @@ const page = () => { | |
|
||
<h2>6. Limitation of Liability</h2> | ||
<p> | ||
<strong>6.1. Disclaimer:</strong> CodeRacer is provided "as is," and we make no warranties or representations about the accuracy or reliability of the platform. Your use of CodeRacer is at your own risk. | ||
<strong>6.1. Disclaimer:</strong> CodeRacer is provided {`"as is,"`} and we make no warranties or representations about the accuracy or reliability of the platform. Your use of CodeRacer is at your own risk. | ||
</p> | ||
|
||
<h2>7. Changes to Terms</h2> | ||
|
@@ -58,6 +58,7 @@ const page = () => { | |
<strong>8.1. Questions:</strong> If you have any questions or concerns about these Terms, please contact us at <a href="mailto:[email protected]">[email protected]</a>. | ||
</p> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't you think it has to be called on the server?
Otherwise I could get the result of it (tokenAndStamp) in the network tab
and then make a call to saveUserResultAction with invalid cpm amount