Skip to content

Commit f1cf2fa

Browse files
committed
Fix API key redirect URL schema on in-app wallet settings and unresponsive general project settings page (#5747)
## Problem solved Fixes: DASH-629 <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on updating the validation schema and related components for project settings, particularly around custom authentication endpoints and redirect URIs. The changes enhance the form handling and validation logic in the dashboard. ### Detailed summary - Introduced `expandCustomAuthEndpointField` for conditional rendering of custom authentication endpoint fields. - Updated `checked` property of `GatedSwitch` to use the new variable. - Modified the placeholder of `Textarea` in `NativeAppsFieldset`. - Changed `UpdateAPIForm` type to use `ProjectSettingsPageFormSchema`. - Updated form initialization to use `projectSettingsPageFormSchema`. - Refined validation logic for redirect URIs, allowing specific formats. - Created a new `redirectUriSchema` for validating redirect URIs. - Updated `redirectUrls` validation to use the new schema. - Changed the exported validation type from `ApiKeyValidationSchema` to `ProjectSettingsPageFormSchema`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 7819e1e commit f1cf2fa

File tree

3 files changed

+64
-28
lines changed

3 files changed

+64
-28
lines changed

apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPage.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ import { type FieldArrayWithId, useFieldArray } from "react-hook-form";
3535
import { toast } from "sonner";
3636
import { joinWithComma, toArrFromList } from "utils/string";
3737
import {
38-
type ApiKeyValidationSchema,
3938
HIDDEN_SERVICES,
40-
apiKeyValidationSchema,
39+
type ProjectSettingsPageFormSchema,
40+
projectSettingsPageFormSchema,
4141
} from "../../../../../components/settings/ApiKeys/validations";
4242

4343
type EditProjectUIPaths = {
@@ -86,16 +86,16 @@ interface EditApiKeyProps {
8686
showNebulaSettings: boolean;
8787
}
8888

89-
type UpdateAPIForm = UseFormReturn<ApiKeyValidationSchema>;
89+
type UpdateAPIForm = UseFormReturn<ProjectSettingsPageFormSchema>;
9090

9191
export const ProjectGeneralSettingsPageUI: React.FC<EditApiKeyProps> = (
9292
props,
9393
) => {
9494
const { apiKey, updateMutation, deleteMutation } = props;
9595
const trackEvent = useTrack();
9696
const router = useDashboardRouter();
97-
const form = useForm<ApiKeyValidationSchema>({
98-
resolver: zodResolver(apiKeyValidationSchema),
97+
const form = useForm<ProjectSettingsPageFormSchema>({
98+
resolver: zodResolver(projectSettingsPageFormSchema),
9999
defaultValues: {
100100
name: apiKey.name,
101101
domains: joinWithComma(apiKey.domains),
@@ -484,7 +484,7 @@ function EnabledServicesSetting(props: {
484484
});
485485
const handleAction = (
486486
srvIdx: number,
487-
srv: FieldArrayWithId<ApiKeyValidationSchema, "services", "id">,
487+
srv: FieldArrayWithId<ProjectSettingsPageFormSchema, "services", "id">,
488488
actionName: string,
489489
checked: boolean,
490490
) => {

apps/dashboard/src/components/embedded-wallets/Configure/index.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ function AuthEndpointFields(props: {
422422
name: "customAuthEndpoint.customHeaders",
423423
});
424424

425+
const expandCustomAuthEndpointField =
426+
form.watch("customAuthEndpoint")?.authEndpoint !== undefined &&
427+
canEditAdvancedFeatures;
428+
425429
return (
426430
<div>
427431
<SwitchContainer
@@ -445,9 +449,7 @@ function AuthEndpointFields(props: {
445449
>
446450
<GatedSwitch
447451
trackingLabel="customAuthEndpoint"
448-
checked={
449-
!!form.watch("customAuthEndpoint") && canEditAdvancedFeatures
450-
}
452+
checked={expandCustomAuthEndpointField}
451453
upgradeRequired={!canEditAdvancedFeatures}
452454
onCheckedChange={(checked) => {
453455
form.setValue(
@@ -464,7 +466,7 @@ function AuthEndpointFields(props: {
464466
</SwitchContainer>
465467

466468
<AdvancedConfigurationContainer
467-
show={canEditAdvancedFeatures && !!form.watch("customAuthEndpoint")}
469+
show={expandCustomAuthEndpointField}
468470
className="grid grid-cols-1 gap-6 lg:grid-cols-2"
469471
>
470472
<FormField
@@ -561,7 +563,10 @@ function NativeAppsFieldset(props: {
561563
<FormItem>
562564
<FormLabel>Allowed redirect URIs</FormLabel>
563565
<FormControl>
564-
<Textarea {...field} placeholder="appName://" />
566+
<Textarea
567+
{...field}
568+
placeholder="appName://, localhost:3000, https://example.com"
569+
/>
565570
</FormControl>
566571
<FormDescription>
567572
Enter redirect URIs separated by commas or new lines. This is

apps/dashboard/src/components/settings/ApiKeys/validations.ts

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const nameValidation = z
1111
const domainsValidation = z.string().refine(
1212
(str) =>
1313
validStrList(str, (domain) => {
14-
return domain.split(":")[0] === "localhost" || RE_DOMAIN.test(domain);
14+
return domain.startsWith("localhost:") || RE_DOMAIN.test(domain);
1515
}),
1616
{
1717
message: "Some of the domains are invalid",
@@ -95,26 +95,55 @@ export const apiKeyCreateValidationSchema = z.object({
9595
services: servicesValidation,
9696
});
9797

98-
export const apiKeyValidationSchema = z.object({
98+
function isValidRedirectURI(uri: string) {
99+
// whitespace is not allowed
100+
if (/\s/g.test(uri)) {
101+
return false;
102+
}
103+
104+
// foo://... is allowed
105+
if (uri.includes("://")) {
106+
return true;
107+
}
108+
109+
// localhost:... is allowed
110+
if (uri.startsWith("localhost:")) {
111+
return true;
112+
}
113+
114+
// valid url is allowed
115+
try {
116+
new URL(uri);
117+
return true;
118+
} catch {
119+
// invalid
120+
}
121+
122+
// everything else is invalid
123+
return false;
124+
}
125+
126+
const redirectUriSchema = z
127+
.string()
128+
.refine((str) => validStrList(str, isValidRedirectURI), {
129+
message:
130+
"Some of the redirect URIs are invalid. Make sure they are valid URIs and do not contain spaces.",
131+
})
132+
.refine((str) => str !== "*", {
133+
message: "Wildcard redirect URIs are not allowed",
134+
});
135+
136+
// TODO: move this schema to project settings folder in separate PR
137+
export const projectSettingsPageFormSchema = z.object({
99138
name: nameValidation,
100139
domains: domainsValidation,
101140
services: servicesValidation,
102141
bundleIds: z.string().refine((str) => validStrList(str, RE_BUNDLE_ID), {
103142
message: "Some of the bundle ids are invalid",
104143
}),
105-
redirectUrls: z
106-
.string()
107-
.refine(
108-
(str) =>
109-
validStrList(str, (url) => url.includes("://") && !/\s/g.test(url)),
110-
{
111-
message:
112-
"Some of the redirect URIs are invalid. Make sure they are valid URIs and do not contain spaces.",
113-
},
114-
)
115-
.refine((str) => str !== "*", {
116-
message: "Wildcard redirect URIs are not allowed",
117-
}),
144+
// no strict validation for redirectUrls, because project general page does not render redirectUrls form field
145+
// so if the user has already saved an invalid `redirectUrls` on in-app wallet project settings page ( which is fixed now ) - it won't prevent them from updating the general project settings
146+
redirectUrls: z.string(),
118147
});
119148

120149
export const apiKeyEmbeddedWalletsValidationSchema = z.object({
@@ -127,7 +156,7 @@ export const apiKeyEmbeddedWalletsValidationSchema = z.object({
127156
applicationImageUrl: applicationImageUrlValidation,
128157
}),
129158
]),
130-
redirectUrls: z.union([z.undefined(), z.string()]),
159+
redirectUrls: redirectUriSchema,
131160
});
132161

133162
export const apiKeyPayConfigValidationSchema = z.object({
@@ -138,7 +167,9 @@ export type ApiKeyCreateValidationSchema = z.infer<
138167
typeof apiKeyCreateValidationSchema
139168
>;
140169

141-
export type ApiKeyValidationSchema = z.infer<typeof apiKeyValidationSchema>;
170+
export type ProjectSettingsPageFormSchema = z.infer<
171+
typeof projectSettingsPageFormSchema
172+
>;
142173

143174
export type ApiKeyEmbeddedWalletsValidationSchema = z.infer<
144175
typeof apiKeyEmbeddedWalletsValidationSchema

0 commit comments

Comments
 (0)