Skip to content

Commit fd6fa64

Browse files
committed
Fix API key redirect URL on in-app wallet settings and unresponsive general project settings page
1 parent 6994310 commit fd6fa64

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)