Quellcode durchsuchen

Merge pull request #537 from zzwt/feature/change-link-password

feat: change link password
Pouria Ezzati vor 3 Jahren
Ursprung
Commit
987bafdf36

+ 34 - 4
client/components/LinksTable.tsx

@@ -116,6 +116,7 @@ interface EditForm {
   address: string;
   description?: string;
   expire_in?: string;
+  password?: string;
 }
 
 const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => {
@@ -123,7 +124,7 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => {
   const ban = useStoreActions(s => s.links.ban);
   const edit = useStoreActions(s => s.links.edit);
   const [banFormState, { checkbox }] = useFormState<BanForm>();
-  const [editFormState, { text, label }] = useFormState<EditForm>(
+  const [editFormState, { text, label, password }] = useFormState<EditForm>(
     {
       target: link.target,
       address: link.address,
@@ -132,7 +133,8 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => {
         ? ms(differenceInMilliseconds(new Date(link.expire_in), new Date()), {
             long: true
           })
-        : ""
+        : "",
+      password: ""
     },
     { withIds: true }
   );
@@ -175,6 +177,7 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => {
     } catch (err) {
       setEditMessage(errorMessage(err));
     }
+    editFormState.setField("password", "");
     setEditLoading(false);
   };
 
@@ -355,7 +358,7 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => {
                   />
                 </Flex>
               </Col>
-              <Col alignItems="flex-start">
+              <Col alignItems="flex-start" mr={3}>
                 <Text
                   {...label("address")}
                   as="label"
@@ -379,6 +382,33 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => {
                   />
                 </Flex>
               </Col>
+              <Col alignItems="flex-start">
+                <Text
+                  {...label("password")}
+                  as="label"
+                  mb={2}
+                  fontSize={[14, 15]}
+                  bold
+                >
+                  Password
+                </Text>
+                <Flex as="form">
+                  <TextInput
+                    {...password({
+                      name: "password"
+                    })}
+                    placeholder={link.password ? "●●●●●●●" : "Password..."}
+                    autocomplete="off"
+                    data-lpignore
+                    pl={[3, 24]}
+                    pr={[3, 24]}
+                    placeholderSize={[13, 14]}
+                    fontSize={[14, 15]}
+                    height={[40, 44]}
+                    width={[1, 210, 240]}
+                  />
+                </Flex>
+              </Col>
             </Flex>
             <Flex alignItems="flex-start" width={1} mt={3}>
               <Col alignItems="flex-start" mr={3}>
@@ -613,7 +643,7 @@ const LinksTable: FC = () => {
       <H2 mb={3} light>
         Recent shortened links.
       </H2>
-      <Table scrollWidth="800px">
+      <Table scrollWidth="1000px">
         <thead>
           <Tr justifyContent="space-between">
             <Th flexGrow={1} flexShrink={1}>

+ 3 - 3
server/handlers/links.ts

@@ -108,8 +108,7 @@ export const create: Handler = async (req: CreateLinkReq, res) => {
 };
 
 export const edit: Handler = async (req, res) => {
-  const { address, target, description, expire_in } = req.body;
-
+  const { address, target, description, expire_in, password } = req.body;
   if (!address && !target) {
     throw new CustomError("Should at least update one field.");
   }
@@ -152,7 +151,8 @@ export const edit: Handler = async (req, res) => {
       ...(address && { address }),
       ...(description && { description }),
       ...(target && { target }),
-      ...(expire_in && { expire_in })
+      ...(expire_in && { expire_in }),
+      ...(password && { password })
     }
   );
 

+ 7 - 0
server/handlers/validators.ts

@@ -145,6 +145,13 @@ export const editLink = [
     .withMessage("URL is not valid.")
     .custom(value => removeWww(URL.parse(value).host) !== env.DEFAULT_DOMAIN)
     .withMessage(`${env.DEFAULT_DOMAIN} URLs are not allowed.`),
+  body("password")
+    .optional({ nullable: true, checkFalsy: true })
+    .custom(checkUser)
+    .withMessage("Only users can use this field.")
+    .isString()
+    .isLength({ min: 3, max: 64 })
+    .withMessage("Password length must be between 3 and 64."),
   body("address")
     .optional({ checkFalsy: true, nullable: true })
     .isString()

+ 5 - 0
server/queries/link.ts

@@ -180,6 +180,11 @@ export const batchRemove = async (match: Match<Link>) => {
 };
 
 export const update = async (match: Partial<Link>, update: Partial<Link>) => {
+  if (update.password) {
+    const salt = await bcrypt.genSalt(12);
+    update.password = await bcrypt.hash(update.password, salt);
+  }
+
   const links = await knex<Link>("links")
     .where(match)
     .update({ ...update, updated_at: new Date().toISOString() }, "*");