-
Notifications
You must be signed in to change notification settings - Fork 72
Feat: Re implement functional authcontroller and connect use cases #147
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
Changes from 2 commits
c881078
0b7397e
28749b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /* | ||
| Warnings: | ||
|
|
||
| - The primary key for the `UserVolunteer` table will be changed. If it partially fails, the table could be left without primary key constraint. | ||
| - You are about to drop the column `id` on the `UserVolunteer` table. All the data in the column will be lost. | ||
|
|
||
| */ | ||
| -- DropForeignKey | ||
| ALTER TABLE "Certificate" DROP CONSTRAINT "Certificate_volunteerId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "CertificateDownloadLog" DROP CONSTRAINT "CertificateDownloadLog_certificateId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "NFT" DROP CONSTRAINT "NFT_organizationId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "NFT" DROP CONSTRAINT "NFT_userId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "Project" DROP CONSTRAINT "Project_organizationId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "UserVolunteer" DROP CONSTRAINT "UserVolunteer_userId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "UserVolunteer" DROP CONSTRAINT "UserVolunteer_volunteerId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "Volunteer" DROP CONSTRAINT "Volunteer_projectId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "escrows" DROP CONSTRAINT "escrows_user_id_fkey"; | ||
|
|
||
| -- DropIndex | ||
| DROP INDEX "UserVolunteer_userId_volunteerId_key"; | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "Project" ADD COLUMN "status" TEXT NOT NULL DEFAULT 'active'; | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "User" ADD COLUMN "verificationTokenExpires" TIMESTAMP(3); | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "UserVolunteer" DROP CONSTRAINT "UserVolunteer_pkey", | ||
| DROP COLUMN "id", | ||
| ADD COLUMN "hoursContributed" DOUBLE PRECISION NOT NULL DEFAULT 0, | ||
| ADD CONSTRAINT "UserVolunteer_pkey" PRIMARY KEY ("userId", "volunteerId"); | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "Volunteer" ADD COLUMN "maxVolunteers" INTEGER NOT NULL DEFAULT 10; | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "Message" ( | ||
| "id" TEXT NOT NULL, | ||
| "content" TEXT NOT NULL, | ||
| "sentAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "readAt" TIMESTAMP(3), | ||
| "senderId" TEXT NOT NULL, | ||
| "receiverId" TEXT NOT NULL, | ||
| "volunteerId" TEXT NOT NULL, | ||
|
|
||
| CONSTRAINT "Message_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "Message_senderId_idx" ON "Message"("senderId"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "Message_receiverId_idx" ON "Message"("receiverId"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "Message_volunteerId_idx" ON "Message"("volunteerId"); | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| import { Request, Response } from "express"; | ||
|
|
||
| // imports for DTO validator | ||
| import { plainToInstance } from "class-transformer"; | ||
| import { validate } from "class-validator"; | ||
|
|
||
| // Necessary DTOs | ||
| import { RegisterDto } from "../../dto/register.dto"; | ||
| import { LoginDto } from "../../dto/login.dto"; | ||
| import { ResendVerificationDTO } from "../../dto/resendVerificationDTO"; | ||
| import { | ||
| VerifyWalletDto, | ||
| ValidateWalletFormatDto, | ||
| } from "../../dto/wallet-validation.dto"; | ||
|
|
||
| // Use cases | ||
| import { PrismaUserRepository } from "../../../user/repositories/PrismaUserRepository"; | ||
| import { SendVerificationEmailUseCase } from "../../use-cases/send-verification-email.usecase"; | ||
| import { ResendVerificationEmailUseCase } from "../../use-cases/resend-verification-email.usecase"; | ||
| import { VerifyEmailUseCase } from "../../use-cases/verify-email.usecase"; | ||
| import { ValidateWalletFormatUseCase } from "../../use-cases/wallet-format-validation.usecase"; | ||
| import { VerifyWalletUseCase } from "../../use-cases/verify-wallet.usecase"; | ||
|
|
||
| const userRepository = new PrismaUserRepository(); | ||
| const sendVerificationEmailUseCase = new SendVerificationEmailUseCase( | ||
| userRepository | ||
| ); | ||
| const resendVerificationEmailUseCase = new ResendVerificationEmailUseCase( | ||
| userRepository | ||
| ); | ||
| const verifyEmailUseCase = new VerifyEmailUseCase(userRepository); | ||
| const validateWalletFormatUseCase = new ValidateWalletFormatUseCase(); | ||
| const verifyWalletUseCase = new VerifyWalletUseCase(); | ||
|
|
||
| // DTO validator | ||
| async function validateOr400<T>( | ||
| Cls: new () => T, | ||
| payload: unknown, | ||
| res: Response | ||
| ): Promise<T | undefined> { | ||
| const dto = plainToInstance(Cls, payload); | ||
| const errors = await validate(dto as object, { | ||
| whitelist: true, | ||
| forbidNonWhitelisted: true, | ||
| }); | ||
|
|
||
| // dto not verified, throw a Bad Request | ||
| if (errors.length) { | ||
| res.status(400).json({ message: "Validation failed", errors }); | ||
| return; | ||
| } | ||
|
|
||
| return dto; | ||
| } | ||
|
|
||
| const register = async (req: Request, res: Response) => { | ||
| const dto = await validateOr400(RegisterDto, req.body, res); | ||
| if (!dto) return; | ||
|
|
||
| try { | ||
| // Send verification email to provided address | ||
| await sendVerificationEmailUseCase.execute({ email: dto.email }); | ||
| res.status(200).json({ message: "Verification email sent" }); | ||
| } catch (err) { | ||
| const message = | ||
| err instanceof Error ? err.message : "Failed to send verification email"; | ||
| const status = message === "User not found" ? 400 : 500; | ||
| res.status(status).json({ error: message }); | ||
| } | ||
| }; | ||
|
|
||
| const login = async (req: Request, res: Response) => { | ||
| const dto = await validateOr400(LoginDto, req.body, res); | ||
| if (!dto) return; | ||
|
|
||
| // TODO: Implement Wallet auth logic as a use case | ||
| res.status(501).json({ | ||
| message: "Login service temporarily disabled", | ||
| error: "Wallet auth logic not implemented yet", | ||
| }); | ||
| }; | ||
|
|
||
| const resendVerificationEmail = async (req: Request, res: Response) => { | ||
| const dto = await validateOr400(ResendVerificationDTO, req.body, res); | ||
| if (!dto) return; | ||
|
|
||
| try { | ||
| // Resends verification email to provided address | ||
| await resendVerificationEmailUseCase.execute({ email: dto.email }); | ||
| res.status(200).json({ message: "Verification email resent" }); | ||
| } catch (err) { | ||
| const message = | ||
| err instanceof Error | ||
| ? err.message | ||
| : "Failed to resend verification email"; | ||
| const status = message === "User not found" ? 404 : 500; | ||
| res.status(status).json({ error: message }); | ||
| } | ||
| }; | ||
|
|
||
| const verifyEmail = async (req: Request, res: Response) => { | ||
| const tokenParam = | ||
| typeof req.params.token === "string" ? req.params.token : undefined; | ||
| const tokenQuery = | ||
| typeof req.query.token === "string" | ||
| ? (req.query.token as string) | ||
| : undefined; | ||
| const token = tokenParam || tokenQuery; | ||
|
|
||
| // if token is not given in the request | ||
| if (!token) { | ||
| res.status(400).json({ | ||
| success: false, | ||
| message: "Token in URL is required", | ||
| verified: false, | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| // Verifies email using use case | ||
| const result = await verifyEmailUseCase.execute({ token }); | ||
| const status = result.success ? 200 : 400; | ||
| res.status(status).json(result); | ||
| } catch { | ||
| res.status(400).json({ | ||
| success: false, | ||
| message: "Invalid or expired verification token", | ||
| verified: false, | ||
| }); | ||
| } | ||
| }; | ||
|
|
||
| const verifyWallet = async (req: Request, res: Response) => { | ||
| const dto = await validateOr400(VerifyWalletDto, req.body, res); | ||
| if (!dto) return; | ||
|
|
||
| try { | ||
| const result = await verifyWalletUseCase.execute(dto); | ||
| const status = result.verified ? 200 : 400; | ||
| res.status(status).json(result); | ||
| } catch (err) { | ||
| const message = | ||
| err instanceof Error ? err.message : "Wallet verification failed"; | ||
| res.status(500).json({ error: message }); | ||
| } | ||
| }; | ||
|
|
||
| const validateWalletFormat = async (req: Request, res: Response) => { | ||
| const dto = await validateOr400(ValidateWalletFormatDto, req.body, res); | ||
| if (!dto) return; | ||
|
|
||
| try { | ||
| // Validates wallet format using use case | ||
| const result = await validateWalletFormatUseCase.execute(dto); | ||
| const status = result.valid ? 200 : 400; | ||
| res.status(status).json(result); | ||
| } catch (err) { | ||
| const message = | ||
| err instanceof Error ? err.message : "Wallet format validation failed"; | ||
| res.status(500).json({ error: message }); | ||
| } | ||
| }; | ||
|
|
||
| export default { | ||
| register, | ||
| login, | ||
| resendVerificationEmail, | ||
| verifyEmail, | ||
| verifyWallet, | ||
| validateWalletFormat, | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Keypair, StrKey, Horizon } from "@stellar/stellar-sdk"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { VerifyWalletDto } from "../dto/wallet-validation.dto"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { horizonConfig } from "../../../config/horizon.config"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type WalletVerificationResult = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class VerifyWalletUseCase { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async execute(input: VerifyWalletDto): Promise<WalletVerificationResult> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { walletAddress, signature, message } = input; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Validate public key format | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!StrKey.isValidEd25519PublicKey(walletAddress)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: "Invalid Stellar public key", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check that account exists on Horizon network before signature verification | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const server = new Horizon.Server(horizonConfig.url, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allowHttp: horizonConfig.url.startsWith("http://"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await server.accounts().accountId(walletAddress).call(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err: unknown) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+30
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.
-import { Keypair, StrKey, Horizon } from "@stellar/stellar-sdk";
+import { Keypair, StrKey, Server } from "@stellar/stellar-sdk";
-const server = new Horizon.Server(horizonConfig.url, {
+const server = new Server(horizonConfig.url, {
allowHttp: horizonConfig.url.startsWith("http://"),
});Update the import and instantiation to prevent a production crash. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type HttpError = { response?: { status?: number } }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const httpErr = err as HttpError; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If account not found on network, error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (httpErr.response?.status === 404) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: "Account not found on Stellar network", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: err instanceof Error ? err.message : "Horizon query failed", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Decode signature (expect base64) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let sig: Buffer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sig = Buffer.from(signature, "base64"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: "Invalid signature encoding (base64)", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!sig || sig.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { verified: false, walletAddress, error: "Empty signature" }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = Buffer.from(message, "utf8"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const keypair = Keypair.fromPublicKey(walletAddress); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const keypairVerification = keypair.verify(data, sig); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return keypairVerification | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? { verified: true, walletAddress } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: "Signature verification failed", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verified: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| walletAddress, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: err instanceof Error ? err.message : "Verification error", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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.
Referential integrity lost – foreign keys dropped but never re-added
The migration removes every FK on Certificate, NFT, Project, UserVolunteer, Volunteer and
escrowsyet does not recreate them afterwards.This leaves the DB without critical constraints, allowing orphaned rows and breaking Prisma’s relation expectations.
Re-add the FKs (with
ON DELETE …clauses matching domain rules) in the same migration or a follow-up script before shipping.🤖 Prompt for AI Agents