Update and refine schemas in Stripe and Team Accounts features

Refactored both Stripe and Team Accounts features' schemas for better data validation and added specificity to keys. Enhanced form validations with methods to ensure Stripe keys follow appropriate prefixes. Replaced generic string types with UUID for accountId attributes in different services. Also turned off autocomplete for destructive actions for improved security.
This commit is contained in:
giancarlo
2024-03-29 18:03:41 +08:00
parent af908ae685
commit 59c08c59d7
10 changed files with 55 additions and 25 deletions

View File

@@ -5,7 +5,7 @@ import { LineItemUsageType, PaymentType } from '../create-billing-schema';
export const CreateBillingCheckoutSchema = z
.object({
returnUrl: z.string().url(),
accountId: z.string(),
accountId: z.string().uuid(),
paymentType: PaymentType,
lineItems: z.array(
z.object({
@@ -16,7 +16,7 @@ export const CreateBillingCheckoutSchema = z
),
trialDays: z.number().optional(),
customerId: z.string().optional(),
customerEmail: z.string().optional(),
customerEmail: z.string().email().optional(),
})
.refine(
(schema) => {

View File

@@ -1,6 +1,6 @@
import { z } from 'zod';
export const LeaveTeamAccountSchema = z.object({
accountId: z.string(),
accountId: z.string().uuid(),
confirmation: z.custom((value) => value === 'LEAVE'),
});

View File

@@ -1,8 +1,6 @@
import { z } from 'zod';
type Role = string;
export const UpdateInvitationSchema = z.object({
invitationId: z.number(),
role: z.custom<Role>(() => z.string().min(1)),
role: z.string().min(1),
});

View File

@@ -7,8 +7,8 @@ import { Logger } from '@kit/shared/logger';
import { Database } from '@kit/supabase/database';
const Schema = z.object({
accountId: z.string(),
userId: z.string(),
accountId: z.string().uuid(),
userId: z.string().uuid(),
});
export class LeaveTeamAccountService {

View File

@@ -3,7 +3,9 @@ import { z } from 'zod';
export const MailerSchema = z
.object({
to: z.string().email(),
from: z.string().email(),
// this is not necessarily formatted
// as an email so we type it loosely
from: z.string().min(1),
subject: z.string(),
})
.and(

View File

@@ -2,7 +2,6 @@
import { useState } from 'react';
import { invariant } from '@epic-web/invariant';
import {
EmbeddedCheckout,
EmbeddedCheckoutProvider,
@@ -16,11 +15,13 @@ import {
DialogTitle,
} from '@kit/ui/dialog';
const STRIPE_PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;
import { StripeClientEnvSchema } from '../schema/stripe-client-env.schema';
invariant(STRIPE_PUBLISHABLE_KEY, 'Stripe publishable key is required');
const { publishableKey } = StripeClientEnvSchema.parse({
publishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
});
const stripePromise = loadStripe(STRIPE_PUBLISHABLE_KEY);
const stripePromise = loadStripe(publishableKey);
export function StripeCheckout({
checkoutToken,

View File

@@ -1,5 +1,15 @@
import { z } from 'zod';
export const StripeClientEnvSchema = z.object({
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
});
export const StripeClientEnvSchema = z
.object({
publishableKey: z.string().min(1),
})
.refine(
(schema) => {
return schema.publishableKey.startsWith('pk_');
},
{
path: ['publishableKey'],
message: `Stripe publishable key must start with 'pk_'`,
},
);

View File

@@ -1,6 +1,25 @@
import { z } from 'zod';
export const StripeServerEnvSchema = z.object({
STRIPE_SECRET_KEY: z.string().min(1),
STRIPE_WEBHOOK_SECRET: z.string().min(1),
});
export const StripeServerEnvSchema = z
.object({
secretKey: z.string().min(1),
webhooksSecret: z.string().min(1),
})
.refine(
(schema) => {
return schema.secretKey.startsWith('sk_');
},
{
path: ['STRIPE_SECRET_KEY'],
message: `Stripe secret key must start with 'sk_'`,
},
)
.refine(
(schema) => {
return schema.webhooksSecret.startsWith('whsec_');
},
{
path: ['STRIPE_WEBHOOK_SECRET'],
message: `Stripe webhook secret must start with 'whsec_'`,
},
);

View File

@@ -16,7 +16,7 @@ export async function createStripeClient() {
STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
});
return new Stripe(stripeServerEnv.STRIPE_SECRET_KEY, {
return new Stripe(stripeServerEnv.secretKey, {
apiVersion: STRIPE_API_VERSION,
});
}

View File

@@ -32,9 +32,9 @@ export class StripeWebhookHandlerService
const signatureKey = `stripe-signature`;
const signature = request.headers.get(signatureKey)!;
const { STRIPE_WEBHOOK_SECRET } = StripeServerEnvSchema.parse({
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
const { webhooksSecret } = StripeServerEnvSchema.parse({
secretKey: process.env.STRIPE_SECRET_KEY,
webhooksSecret: process.env.STRIPE_WEBHOOK_SECRET,
});
const stripe = await this.loadStripe();
@@ -42,7 +42,7 @@ export class StripeWebhookHandlerService
const event = stripe.webhooks.constructEvent(
body,
signature,
STRIPE_WEBHOOK_SECRET,
webhooksSecret,
);
if (!event) {