Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ import { type FieldArrayWithId, useFieldArray } from "react-hook-form";
import { toast } from "sonner";
import { joinWithComma, toArrFromList } from "utils/string";
import {
type ApiKeyValidationSchema,
HIDDEN_SERVICES,
apiKeyValidationSchema,
type ProjectSettingsPageFormSchema,
projectSettingsPageFormSchema,
} from "../../../../../components/settings/ApiKeys/validations";

type EditProjectUIPaths = {
Expand Down Expand Up @@ -86,16 +86,16 @@ interface EditApiKeyProps {
showNebulaSettings: boolean;
}

type UpdateAPIForm = UseFormReturn<ApiKeyValidationSchema>;
type UpdateAPIForm = UseFormReturn<ProjectSettingsPageFormSchema>;

export const ProjectGeneralSettingsPageUI: React.FC<EditApiKeyProps> = (
props,
) => {
const { apiKey, updateMutation, deleteMutation } = props;
const trackEvent = useTrack();
const router = useDashboardRouter();
const form = useForm<ApiKeyValidationSchema>({
resolver: zodResolver(apiKeyValidationSchema),
const form = useForm<ProjectSettingsPageFormSchema>({
resolver: zodResolver(projectSettingsPageFormSchema),
defaultValues: {
name: apiKey.name,
domains: joinWithComma(apiKey.domains),
Expand Down Expand Up @@ -484,7 +484,7 @@ function EnabledServicesSetting(props: {
});
const handleAction = (
srvIdx: number,
srv: FieldArrayWithId<ApiKeyValidationSchema, "services", "id">,
srv: FieldArrayWithId<ProjectSettingsPageFormSchema, "services", "id">,
actionName: string,
checked: boolean,
) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,10 @@ function AuthEndpointFields(props: {
name: "customAuthEndpoint.customHeaders",
});

const expandCustomAuthEndpointField =
form.watch("customAuthEndpoint")?.authEndpoint !== undefined &&
canEditAdvancedFeatures;

return (
<div>
<SwitchContainer
Expand All @@ -445,9 +449,7 @@ function AuthEndpointFields(props: {
>
<GatedSwitch
trackingLabel="customAuthEndpoint"
checked={
!!form.watch("customAuthEndpoint") && canEditAdvancedFeatures
}
checked={expandCustomAuthEndpointField}
upgradeRequired={!canEditAdvancedFeatures}
onCheckedChange={(checked) => {
form.setValue(
Expand All @@ -464,7 +466,7 @@ function AuthEndpointFields(props: {
</SwitchContainer>

<AdvancedConfigurationContainer
show={canEditAdvancedFeatures && !!form.watch("customAuthEndpoint")}
show={expandCustomAuthEndpointField}
className="grid grid-cols-1 gap-6 lg:grid-cols-2"
>
<FormField
Expand Down Expand Up @@ -561,7 +563,10 @@ function NativeAppsFieldset(props: {
<FormItem>
<FormLabel>Allowed redirect URIs</FormLabel>
<FormControl>
<Textarea {...field} placeholder="appName://" />
<Textarea
{...field}
placeholder="appName://, localhost:3000, https://example.com"
/>
</FormControl>
<FormDescription>
Enter redirect URIs separated by commas or new lines. This is
Expand Down
65 changes: 48 additions & 17 deletions apps/dashboard/src/components/settings/ApiKeys/validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const nameValidation = z
const domainsValidation = z.string().refine(
(str) =>
validStrList(str, (domain) => {
return domain.split(":")[0] === "localhost" || RE_DOMAIN.test(domain);
return domain.startsWith("localhost:") || RE_DOMAIN.test(domain);
}),
{
message: "Some of the domains are invalid",
Expand Down Expand Up @@ -95,26 +95,55 @@ export const apiKeyCreateValidationSchema = z.object({
services: servicesValidation,
});

export const apiKeyValidationSchema = z.object({
function isValidRedirectURI(uri: string) {
// whitespace is not allowed
if (/\s/g.test(uri)) {
return false;
}

// foo://... is allowed
if (uri.includes("://")) {
return true;
}

// localhost:... is allowed
if (uri.startsWith("localhost:")) {
return true;
}

// valid url is allowed
try {
new URL(uri);
return true;
} catch {
// invalid
}

// everything else is invalid
return false;
}

const redirectUriSchema = z
.string()
.refine((str) => validStrList(str, isValidRedirectURI), {
message:
"Some of the redirect URIs are invalid. Make sure they are valid URIs and do not contain spaces.",
})
.refine((str) => str !== "*", {
message: "Wildcard redirect URIs are not allowed",
});

// TODO: move this schema to project settings folder in separate PR
export const projectSettingsPageFormSchema = z.object({
name: nameValidation,
domains: domainsValidation,
services: servicesValidation,
bundleIds: z.string().refine((str) => validStrList(str, RE_BUNDLE_ID), {
message: "Some of the bundle ids are invalid",
}),
redirectUrls: z
.string()
.refine(
(str) =>
validStrList(str, (url) => url.includes("://") && !/\s/g.test(url)),
{
message:
"Some of the redirect URIs are invalid. Make sure they are valid URIs and do not contain spaces.",
},
)
.refine((str) => str !== "*", {
message: "Wildcard redirect URIs are not allowed",
}),
// no strict validation for redirectUrls, because project general page does not render redirectUrls form field
// 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
redirectUrls: z.string(),
});

export const apiKeyEmbeddedWalletsValidationSchema = z.object({
Expand All @@ -127,7 +156,7 @@ export const apiKeyEmbeddedWalletsValidationSchema = z.object({
applicationImageUrl: applicationImageUrlValidation,
}),
]),
redirectUrls: z.union([z.undefined(), z.string()]),
redirectUrls: redirectUriSchema,
});

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

export type ApiKeyValidationSchema = z.infer<typeof apiKeyValidationSchema>;
export type ProjectSettingsPageFormSchema = z.infer<
typeof projectSettingsPageFormSchema
>;

export type ApiKeyEmbeddedWalletsValidationSchema = z.infer<
typeof apiKeyEmbeddedWalletsValidationSchema
Expand Down
Loading