feat: add a list of reserved words for username, subdomain and page slug
This commit is contained in:
parent
0b2c0f0d80
commit
9e313e3e0e
|
|
@ -0,0 +1,540 @@
|
|||
const words = [
|
||||
"400",
|
||||
"401",
|
||||
"403",
|
||||
"404",
|
||||
"405",
|
||||
"406",
|
||||
"407",
|
||||
"408",
|
||||
"409",
|
||||
"410",
|
||||
"411",
|
||||
"412",
|
||||
"413",
|
||||
"414",
|
||||
"415",
|
||||
"416",
|
||||
"417",
|
||||
"421",
|
||||
"422",
|
||||
"423",
|
||||
"424",
|
||||
"426",
|
||||
"428",
|
||||
"429",
|
||||
"431",
|
||||
"500",
|
||||
"501",
|
||||
"502",
|
||||
"503",
|
||||
"504",
|
||||
"505",
|
||||
"506",
|
||||
"507",
|
||||
"508",
|
||||
"509",
|
||||
"510",
|
||||
"511",
|
||||
"_domainkey",
|
||||
"about",
|
||||
"about-us",
|
||||
"abuse",
|
||||
"access",
|
||||
"account",
|
||||
"accounts",
|
||||
"ad",
|
||||
"add",
|
||||
"admin",
|
||||
"administration",
|
||||
"administrator",
|
||||
"ads",
|
||||
"ads.txt",
|
||||
"advertise",
|
||||
"advertising",
|
||||
"aes128-ctr",
|
||||
"aes128-gcm",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"aes256-gcm",
|
||||
"affiliate",
|
||||
"affiliates",
|
||||
"ajax",
|
||||
"alert",
|
||||
"alerts",
|
||||
"alpha",
|
||||
"amp",
|
||||
"analytics",
|
||||
"api",
|
||||
"app",
|
||||
"apps",
|
||||
"asc",
|
||||
"assets",
|
||||
"auth",
|
||||
"authentication",
|
||||
"authorize",
|
||||
"autoconfig",
|
||||
"autodiscover",
|
||||
"avatar",
|
||||
"backup",
|
||||
"banner",
|
||||
"banners",
|
||||
"bbs",
|
||||
"beta",
|
||||
"billing",
|
||||
"billings",
|
||||
"blogs",
|
||||
"board",
|
||||
"bookmark",
|
||||
"bookmarks",
|
||||
"broadcasthost",
|
||||
"business",
|
||||
"buy",
|
||||
"cache",
|
||||
"calendar",
|
||||
"campaign",
|
||||
"captcha",
|
||||
"careers",
|
||||
"cart",
|
||||
"cas",
|
||||
"categories",
|
||||
"category",
|
||||
"cdn",
|
||||
"cgi",
|
||||
"cgi-bin",
|
||||
"chacha20-poly1305",
|
||||
"change",
|
||||
"channel",
|
||||
"channels",
|
||||
"chart",
|
||||
"chat",
|
||||
"checkout",
|
||||
"clear",
|
||||
"client",
|
||||
"close",
|
||||
"cloud",
|
||||
"cms",
|
||||
"com",
|
||||
"comment",
|
||||
"comments",
|
||||
"community",
|
||||
"compare",
|
||||
"compose",
|
||||
"config",
|
||||
"connect",
|
||||
"contact",
|
||||
"contest",
|
||||
"cookies",
|
||||
"copy",
|
||||
"copyright",
|
||||
"count",
|
||||
"cp",
|
||||
"cpanel",
|
||||
"create",
|
||||
"crossdomain.xml",
|
||||
"css",
|
||||
"curve25519-sha256",
|
||||
"customer",
|
||||
"customers",
|
||||
"customize",
|
||||
"dashboard",
|
||||
"db",
|
||||
"deals",
|
||||
"debug",
|
||||
"delete",
|
||||
"desc",
|
||||
"destroy",
|
||||
"dev",
|
||||
"developer",
|
||||
"developers",
|
||||
"diffie-hellman-group-exchange-sha256",
|
||||
"diffie-hellman-group14-sha1",
|
||||
"disconnect",
|
||||
"discuss",
|
||||
"dns",
|
||||
"dns0",
|
||||
"dns1",
|
||||
"dns2",
|
||||
"dns3",
|
||||
"dns4",
|
||||
"docs",
|
||||
"documentation",
|
||||
"domain",
|
||||
"download",
|
||||
"downloads",
|
||||
"downvote",
|
||||
"draft",
|
||||
"drop",
|
||||
"ecdh-sha2-nistp256",
|
||||
"ecdh-sha2-nistp384",
|
||||
"ecdh-sha2-nistp521",
|
||||
"edit",
|
||||
"editor",
|
||||
"email",
|
||||
"enterprise",
|
||||
"error",
|
||||
"errors",
|
||||
"event",
|
||||
"events",
|
||||
"example",
|
||||
"exception",
|
||||
"exit",
|
||||
"explore",
|
||||
"export",
|
||||
"extensions",
|
||||
"false",
|
||||
"family",
|
||||
"faq",
|
||||
"faqs",
|
||||
"features",
|
||||
"feed",
|
||||
"feedback",
|
||||
"feeds",
|
||||
"file",
|
||||
"files",
|
||||
"filter",
|
||||
"follow",
|
||||
"follower",
|
||||
"followers",
|
||||
"following",
|
||||
"fonts",
|
||||
"forgot",
|
||||
"forgot-password",
|
||||
"forgotpassword",
|
||||
"form",
|
||||
"forms",
|
||||
"forum",
|
||||
"forums",
|
||||
"friend",
|
||||
"friends",
|
||||
"ftp",
|
||||
"fuck",
|
||||
"get",
|
||||
"git",
|
||||
"go",
|
||||
"graphql",
|
||||
"group",
|
||||
"groups",
|
||||
"guest",
|
||||
"guidelines",
|
||||
"guides",
|
||||
"head",
|
||||
"header",
|
||||
"help",
|
||||
"hide",
|
||||
"hmac-sha",
|
||||
"hmac-sha1",
|
||||
"hmac-sha1-etm",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha2-256-etm",
|
||||
"hmac-sha2-512",
|
||||
"hmac-sha2-512-etm",
|
||||
"home",
|
||||
"host",
|
||||
"hosting",
|
||||
"hostmaster",
|
||||
"htpasswd",
|
||||
"http",
|
||||
"httpd",
|
||||
"https",
|
||||
"icons",
|
||||
"images",
|
||||
"imap",
|
||||
"img",
|
||||
"import",
|
||||
"index",
|
||||
"info",
|
||||
"insert",
|
||||
"investors",
|
||||
"invitations",
|
||||
"invite",
|
||||
"invites",
|
||||
"invoice",
|
||||
"is",
|
||||
"isatap",
|
||||
"issues",
|
||||
"it",
|
||||
"jobs",
|
||||
"join",
|
||||
"js",
|
||||
"json",
|
||||
"learn",
|
||||
"legal",
|
||||
"license",
|
||||
"licensing",
|
||||
"like",
|
||||
"limit",
|
||||
"live",
|
||||
"load",
|
||||
"local",
|
||||
"localdomain",
|
||||
"localhost",
|
||||
"lock",
|
||||
"login",
|
||||
"logout",
|
||||
"lost-password",
|
||||
"mail",
|
||||
"mail0",
|
||||
"mail1",
|
||||
"mail2",
|
||||
"mail3",
|
||||
"mail4",
|
||||
"mail5",
|
||||
"mail6",
|
||||
"mail7",
|
||||
"mail8",
|
||||
"mail9",
|
||||
"mailer-daemon",
|
||||
"mailerdaemon",
|
||||
"map",
|
||||
"marketing",
|
||||
"marketplace",
|
||||
"master",
|
||||
"me",
|
||||
"media",
|
||||
"member",
|
||||
"members",
|
||||
"message",
|
||||
"messages",
|
||||
"metrics",
|
||||
"mis",
|
||||
"mobile",
|
||||
"moderator",
|
||||
"modify",
|
||||
"more",
|
||||
"mx",
|
||||
"mx1",
|
||||
"my",
|
||||
"net",
|
||||
"network",
|
||||
"new",
|
||||
"news",
|
||||
"newsletter",
|
||||
"newsletters",
|
||||
"next",
|
||||
"nil",
|
||||
"no-reply",
|
||||
"nobody",
|
||||
"noc",
|
||||
"none",
|
||||
"noreply",
|
||||
"notification",
|
||||
"notifications",
|
||||
"ns",
|
||||
"ns0",
|
||||
"ns1",
|
||||
"ns2",
|
||||
"ns3",
|
||||
"ns4",
|
||||
"ns5",
|
||||
"ns6",
|
||||
"ns7",
|
||||
"ns8",
|
||||
"ns9",
|
||||
"null",
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"offer",
|
||||
"offers",
|
||||
"online",
|
||||
"openid",
|
||||
"order",
|
||||
"orders",
|
||||
"overview",
|
||||
"owa",
|
||||
"owner",
|
||||
"page",
|
||||
"pages",
|
||||
"partners",
|
||||
"passwd",
|
||||
"password",
|
||||
"pay",
|
||||
"payment",
|
||||
"payments",
|
||||
"paypal",
|
||||
"photo",
|
||||
"photos",
|
||||
"pixel",
|
||||
"plans",
|
||||
"plugins",
|
||||
"policies",
|
||||
"policy",
|
||||
"pop",
|
||||
"pop3",
|
||||
"popular",
|
||||
"portal",
|
||||
"portfolio",
|
||||
"post",
|
||||
"postfix",
|
||||
"postmaster",
|
||||
"poweruser",
|
||||
"preferences",
|
||||
"premium",
|
||||
"press",
|
||||
"previous",
|
||||
"pricing",
|
||||
"print",
|
||||
"privacy",
|
||||
"privacy-policy",
|
||||
"private",
|
||||
"prod",
|
||||
"product",
|
||||
"production",
|
||||
"profile",
|
||||
"profiles",
|
||||
"project",
|
||||
"projects",
|
||||
"promo",
|
||||
"public",
|
||||
"purchase",
|
||||
"put",
|
||||
"quota",
|
||||
"redirect",
|
||||
"reduce",
|
||||
"refund",
|
||||
"refunds",
|
||||
"register",
|
||||
"registration",
|
||||
"remove",
|
||||
"replies",
|
||||
"reply",
|
||||
"report",
|
||||
"request",
|
||||
"request-password",
|
||||
"reset",
|
||||
"reset-password",
|
||||
"response",
|
||||
"return",
|
||||
"returns",
|
||||
"review",
|
||||
"reviews",
|
||||
"root",
|
||||
"rootuser",
|
||||
"rsa-sha2-2",
|
||||
"rsa-sha2-512",
|
||||
"rss",
|
||||
"rules",
|
||||
"sales",
|
||||
"save",
|
||||
"script",
|
||||
"sdk",
|
||||
"search",
|
||||
"secure",
|
||||
"security",
|
||||
"select",
|
||||
"services",
|
||||
"session",
|
||||
"sessions",
|
||||
"settings",
|
||||
"setup",
|
||||
"share",
|
||||
"shift",
|
||||
"shift",
|
||||
"shop",
|
||||
"signin",
|
||||
"signup",
|
||||
"site",
|
||||
"sitemap",
|
||||
"sites",
|
||||
"smtp",
|
||||
"sort",
|
||||
"source",
|
||||
"sql",
|
||||
"ssh",
|
||||
"ssh-rsa",
|
||||
"ssl",
|
||||
"ssladmin",
|
||||
"ssladministrator",
|
||||
"sslwebmaster",
|
||||
"stage",
|
||||
"staging",
|
||||
"stat",
|
||||
"static",
|
||||
"statistics",
|
||||
"stats",
|
||||
"status",
|
||||
"store",
|
||||
"style",
|
||||
"styles",
|
||||
"stylesheet",
|
||||
"stylesheets",
|
||||
"subdomain",
|
||||
"subscribe",
|
||||
"sudo",
|
||||
"super",
|
||||
"superuser",
|
||||
"support",
|
||||
"survey",
|
||||
"sync",
|
||||
"sysadmin",
|
||||
"sysadmin",
|
||||
"system",
|
||||
"tablet",
|
||||
"tag",
|
||||
"tags",
|
||||
"team",
|
||||
"telnet",
|
||||
"terms",
|
||||
"terms-of-use",
|
||||
"test",
|
||||
"testimonials",
|
||||
"theme",
|
||||
"themes",
|
||||
"today",
|
||||
"tools",
|
||||
"topic",
|
||||
"topics",
|
||||
"tour",
|
||||
"training",
|
||||
"translate",
|
||||
"translations",
|
||||
"trending",
|
||||
"trial",
|
||||
"true",
|
||||
"umac-128",
|
||||
"umac-128-etm",
|
||||
"umac-64",
|
||||
"umac-64-etm",
|
||||
"undefined",
|
||||
"unfollow",
|
||||
"unlike",
|
||||
"unsubscribe",
|
||||
"update",
|
||||
"upgrade",
|
||||
"usenet",
|
||||
"user",
|
||||
"username",
|
||||
"users",
|
||||
"uucp",
|
||||
"var",
|
||||
"verify",
|
||||
"video",
|
||||
"view",
|
||||
"void",
|
||||
"vote",
|
||||
"vpn",
|
||||
"webmail",
|
||||
"webmaster",
|
||||
"website",
|
||||
"widget",
|
||||
"widgets",
|
||||
"wiki",
|
||||
"wpad",
|
||||
"write",
|
||||
"www",
|
||||
"www-data",
|
||||
"www1",
|
||||
"www2",
|
||||
"www3",
|
||||
"www4",
|
||||
"you",
|
||||
"yourname",
|
||||
"yourusername",
|
||||
"zlib",
|
||||
]
|
||||
|
||||
export const checkReservedWords = (word: string) => {
|
||||
if (words.includes(word)) {
|
||||
throw new Error(`${word} is a reserved word`)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
import { type Gate } from "~/lib/gate.server"
|
||||
import { sendEmailForNewPost } from "~/lib/mailgun.server"
|
||||
import { getAutoExcerpt, renderPageContent } from "~/lib/markdown.server"
|
||||
import { checkReservedWords } from "~/lib/reserved-words"
|
||||
import { notFound } from "~/lib/server-side-props"
|
||||
import { PageVisibilityEnum } from "~/lib/types"
|
||||
import { isUUID } from "~/lib/uuid"
|
||||
|
|
@ -26,6 +27,9 @@ const checkPageSlug = async ({
|
|||
if (!slug) {
|
||||
throw new Error("Missing page slug")
|
||||
}
|
||||
|
||||
checkReservedWords(slug)
|
||||
|
||||
const page = await prismaPrimary.page.findFirst({
|
||||
where: {
|
||||
siteId,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { sendLoginEmail } from "~/lib/mailgun.server"
|
|||
import { SiteNavigationItem, SubscribeFormData } from "~/lib/types"
|
||||
import { nanoid } from "nanoid"
|
||||
import { getMembership } from "./membership"
|
||||
import { checkReservedWords } from "~/lib/reserved-words"
|
||||
|
||||
export const checkSubdomain = async ({
|
||||
subdomain,
|
||||
|
|
@ -15,6 +16,8 @@ export const checkSubdomain = async ({
|
|||
subdomain: string
|
||||
updatingSiteId?: string
|
||||
}) => {
|
||||
checkReservedWords(subdomain)
|
||||
|
||||
const existingSite = await prismaPrimary.site.findUnique({
|
||||
where: {
|
||||
subdomain,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { prismaPrimary } from "~/lib/db.server"
|
||||
import { Gate } from "~/lib/gate.server"
|
||||
import { checkReservedWords } from "~/lib/reserved-words"
|
||||
|
||||
export const userModel = {
|
||||
async updateProfile(
|
||||
|
|
@ -26,6 +27,8 @@ export const userModel = {
|
|||
}
|
||||
|
||||
if (payload.username) {
|
||||
checkReservedWords(payload.username)
|
||||
|
||||
const userByUsername = await prismaPrimary.user.findUnique({
|
||||
where: {
|
||||
username: payload.username,
|
||||
|
|
|
|||
|
|
@ -13,9 +13,13 @@ export default function AccountProfilePage() {
|
|||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
})
|
||||
const updateProfile = trpc.useMutation("user.updateProfile")
|
||||
const {
|
||||
mutate: updateProfile,
|
||||
status: updateProfileStatus,
|
||||
error: updateProfileError,
|
||||
} = trpc.useMutation("user.updateProfile")
|
||||
|
||||
const form = useForm({
|
||||
const { setValue, handleSubmit, register } = useForm({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
username: "",
|
||||
|
|
@ -24,25 +28,26 @@ export default function AccountProfilePage() {
|
|||
},
|
||||
})
|
||||
|
||||
const handleSubmit = form.handleSubmit((values) => {
|
||||
updateProfile.mutate(values)
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
updateProfile(values)
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (updateProfile.isSuccess) {
|
||||
if (updateProfileStatus === "success") {
|
||||
toast.success("Saved!")
|
||||
updateProfile.reset()
|
||||
} else if (updateProfileStatus === "error" && updateProfileError) {
|
||||
toast.error(updateProfileError.message)
|
||||
}
|
||||
}, [updateProfile])
|
||||
}, [updateProfileStatus, updateProfileError])
|
||||
|
||||
useEffect(() => {
|
||||
if (viewer.data) {
|
||||
form.setValue("name", viewer.data.name)
|
||||
form.setValue("username", viewer.data.username)
|
||||
form.setValue("bio", viewer.data.bio || "")
|
||||
form.setValue("email", viewer.data.email || "")
|
||||
setValue("name", viewer.data.name)
|
||||
setValue("username", viewer.data.username)
|
||||
setValue("bio", viewer.data.bio || "")
|
||||
setValue("email", viewer.data.email || "")
|
||||
}
|
||||
}, [viewer.data, form])
|
||||
}, [viewer.data, setValue])
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
|
|
@ -53,14 +58,14 @@ export default function AccountProfilePage() {
|
|||
<AvatarForm filename={viewer.data.avatar} name={viewer.data.name} />
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="mt-5">
|
||||
<Input
|
||||
label="Display Name"
|
||||
id="name"
|
||||
required
|
||||
type="text"
|
||||
{...form.register("name")}
|
||||
{...register("name")}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
|
|
@ -69,7 +74,7 @@ export default function AccountProfilePage() {
|
|||
id="username"
|
||||
required
|
||||
type="text"
|
||||
{...form.register("username")}
|
||||
{...register("username")}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
|
|
@ -78,11 +83,11 @@ export default function AccountProfilePage() {
|
|||
id="email"
|
||||
required
|
||||
type="email"
|
||||
{...form.register("email")}
|
||||
{...register("email")}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
<Button type="submit" isLoading={updateProfile.isLoading}>
|
||||
<Button type="submit" isLoading={updateProfileStatus === "loading"}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ export default function NewSitePage() {
|
|||
isBlock
|
||||
required
|
||||
addon={`.${OUR_DOMAIN}`}
|
||||
minLength={2}
|
||||
maxLength={20}
|
||||
minLength={3}
|
||||
maxLength={26}
|
||||
{...form.register("subdomain", {})}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ export const siteRouter = createRouter()
|
|||
.mutation("create", {
|
||||
input: z.object({
|
||||
name: z.string(),
|
||||
subdomain: z.string().min(2).max(20),
|
||||
subdomain: z.string().min(3).max(26),
|
||||
}),
|
||||
output: z.object({
|
||||
id: z.string(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue