improvement: add organization name constraint

This commit is contained in:
Scott Wilson
2025-03-06 15:41:27 -08:00
parent 706feafbf2
commit abc2ffca57
7 changed files with 174 additions and 167 deletions
+7
View File
@@ -21,3 +21,10 @@ export const slugSchema = ({ min = 1, max = 32, field = "Slug" }: SlugSchemaInpu
message: `${field} field can only contain lowercase letters, numbers, and hyphens` message: `${field} field can only contain lowercase letters, numbers, and hyphens`
}); });
}; };
export const OrganizationNameSchema = z
.string()
.trim()
.min(1, { message: "Name must be at least 1 character" })
.max(64, { message: "Name must be 64 or fewer characters" })
.regex(/^[a-zA-Z0-9\-_\s]+$/, "Name can only contain alphanumeric characters, dashes, underscores, and spaces");
@@ -13,7 +13,7 @@ import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-t
import { AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs"; import { AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs";
import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn"; import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { slugSchema } from "@app/server/lib/schemas"; import { OrganizationNameSchema, slugSchema } from "@app/server/lib/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ActorType, AuthMode, MfaMethod } from "@app/services/auth/auth-type"; import { ActorType, AuthMode, MfaMethod } from "@app/services/auth/auth-type";
import { sanitizedOrganizationSchema } from "@app/services/org/org-schema"; import { sanitizedOrganizationSchema } from "@app/services/org/org-schema";
@@ -251,7 +251,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
schema: { schema: {
params: z.object({ organizationId: z.string().trim() }), params: z.object({ organizationId: z.string().trim() }),
body: z.object({ body: z.object({
name: z.string().trim().max(64, { message: "Name must be 64 or fewer characters" }).optional(), name: OrganizationNameSchema.optional(),
slug: slugSchema({ max: 64 }).optional(), slug: slugSchema({ max: 64 }).optional(),
authEnforced: z.boolean().optional(), authEnforced: z.boolean().optional(),
scimEnabled: z.boolean().optional(), scimEnabled: z.boolean().optional(),
@@ -12,6 +12,7 @@ import {
import { ORGANIZATIONS } from "@app/lib/api-docs"; import { ORGANIZATIONS } from "@app/lib/api-docs";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { OrganizationNameSchema } from "@app/server/lib/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ActorType, AuthMode } from "@app/services/auth/auth-type"; import { ActorType, AuthMode } from "@app/services/auth/auth-type";
@@ -330,7 +331,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
}, },
schema: { schema: {
body: z.object({ body: z.object({
name: z.string().trim() name: OrganizationNameSchema
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -4,6 +4,7 @@ import { UsersSchema } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { ForbiddenRequestError } from "@app/lib/errors"; import { ForbiddenRequestError } from "@app/lib/errors";
import { authRateLimit } from "@app/server/config/rateLimiter"; import { authRateLimit } from "@app/server/config/rateLimiter";
import { OrganizationNameSchema } from "@app/server/lib/schemas";
import { getServerCfg } from "@app/services/super-admin/super-admin-service"; import { getServerCfg } from "@app/services/super-admin/super-admin-service";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
@@ -100,7 +101,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
encryptedPrivateKeyTag: z.string().trim(), encryptedPrivateKeyTag: z.string().trim(),
salt: z.string().trim(), salt: z.string().trim(),
verifier: z.string().trim(), verifier: z.string().trim(),
organizationName: z.string().trim().min(1), organizationName: OrganizationNameSchema,
providerAuthToken: z.string().trim().optional().nullish(), providerAuthToken: z.string().trim().optional().nullish(),
attributionSource: z.string().trim().optional(), attributionSource: z.string().trim().optional(),
password: z.string() password: z.string()
@@ -11,6 +11,7 @@ import { encodeBase64 } from "tweetnacl-util";
import { initProjectHelper } from "@app/helpers/project"; import { initProjectHelper } from "@app/helpers/project";
import { completeAccountSignup, useSelectOrganization } from "@app/hooks/api/auth/queries"; import { completeAccountSignup, useSelectOrganization } from "@app/hooks/api/auth/queries";
import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries";
import { onRequestError } from "@app/hooks/api/reactQuery";
import InputField from "../basic/InputField"; import InputField from "../basic/InputField";
import checkPassword from "../utilities/checks/password/checkPassword"; import checkPassword from "../utilities/checks/password/checkPassword";
@@ -206,6 +207,7 @@ export default function UserInfoStep({
incrementStep(); incrementStep();
} catch (error) { } catch (error) {
onRequestError(error);
setIsLoading(false); setIsLoading(false);
console.error(error); console.error(error);
} }
@@ -78,7 +78,7 @@ export const CreateOrgModal: FC<CreateOrgModalProps> = ({ isOpen, onClose }) =>
}; };
return ( return (
<Modal isOpen={isOpen}> <Modal modal={false} isOpen={isOpen}>
<ModalContent <ModalContent
title="Create Organization" title="Create Organization"
subTitle="Looks like you're not part of any organizations. Create one to start using Infisical" subTitle="Looks like you're not part of any organizations. Create one to start using Infisical"
+9 -13
View File
@@ -22,9 +22,7 @@ const camelCaseToSpaces = (input: string) => {
return input.replace(/([a-z])([A-Z])/g, "$1 $2"); return input.replace(/([a-z])([A-Z])/g, "$1 $2");
}; };
export const queryClient = new QueryClient({ export const onRequestError = (error: unknown) => {
mutationCache: new MutationCache({
onError: (error) => {
if (axios.isAxiosError(error)) { if (axios.isAxiosError(error)) {
const serverResponse = error.response?.data as TApiErrors; const serverResponse = error.response?.data as TApiErrors;
if (serverResponse?.error === ApiErrorTypes.ValidationError) { if (serverResponse?.error === ApiErrorTypes.ValidationError) {
@@ -121,9 +119,7 @@ export const queryClient = new QueryClient({
if (typeof operators === "string") { if (typeof operators === "string") {
return ( return (
<li <li
key={`Forbidden-error-details-${index + 1}-${ key={`Forbidden-error-details-${index + 1}-${fieldIndex + 1}`}
fieldIndex + 1
}`}
> >
<span className="font-bold capitalize"> <span className="font-bold capitalize">
{formattedFieldName} {formattedFieldName}
@@ -140,9 +136,7 @@ export const queryClient = new QueryClient({
fieldIndex + 1 fieldIndex + 1
}-${operatorIndex + 1}`} }-${operatorIndex + 1}`}
> >
<span className="font-bold capitalize"> <span className="font-bold capitalize">{formattedFieldName}</span>{" "}
{formattedFieldName}
</span>{" "}
<span className="text-mineshaft-200"> <span className="text-mineshaft-200">
{ {
formatedConditionsOperatorNames[ formatedConditionsOperatorNames[
@@ -151,9 +145,7 @@ export const queryClient = new QueryClient({
} }
</span>{" "} </span>{" "}
<span className="text-yellow-600"> <span className="text-yellow-600">
{operators[ {operators[operator as PermissionConditionOperators].toString()}
operator as PermissionConditionOperators
].toString()}
</span> </span>
</li> </li>
)); ));
@@ -192,7 +184,11 @@ export const queryClient = new QueryClient({
] ]
}); });
} }
} };
export const queryClient = new QueryClient({
mutationCache: new MutationCache({
onError: onRequestError
}), }),
defaultOptions: { defaultOptions: {
queries: { queries: {