Browse Source

use zod to validate input

pull/1250/head
Bernd Storath 9 months ago
parent
commit
8850b3cf69
  1. 4
      package.json
  2. 5
      src/package.json
  3. 11
      src/pnpm-lock.yaml
  4. 5
      src/server/api/session.post.ts
  5. 14
      src/server/api/wireguard/client/[clientId]/address.put.ts
  6. 5
      src/server/api/wireguard/client/[clientId]/configuration.get.ts
  7. 12
      src/server/api/wireguard/client/[clientId]/disable.post.ts
  8. 12
      src/server/api/wireguard/client/[clientId]/enable.post.ts
  9. 5
      src/server/api/wireguard/client/[clientId]/index.delete.ts
  10. 14
      src/server/api/wireguard/client/[clientId]/name.put.ts
  11. 5
      src/server/api/wireguard/client/[clientId]/qrcode.svg.get.ts
  12. 2
      src/server/api/wireguard/client/index.post.ts
  13. 2
      src/server/api/wireguard/restore.put.ts
  14. 65
      src/server/utils/types.ts

4
package.json

@ -7,5 +7,5 @@
"sudostart": "sudo docker run --env WG_HOST=0.0.0.0 --name wg-easy --cap-add=NET_ADMIN --cap-add=SYS_MODULE --sysctl=\"net.ipv4.conf.all.src_valid_mark=1\" --mount type=bind,source=\"$(pwd)\"/config,target=/etc/wireguard -p 51820:51820/udp -p 51821:51821/tcp wg-easy",
"start": "docker run --env WG_HOST=0.0.0.0 --name wg-easy --cap-add=NET_ADMIN --cap-add=SYS_MODULE --sysctl=\"net.ipv4.conf.all.src_valid_mark=1\" --mount type=bind,source=\"$(pwd)\"/config,target=/etc/wireguard -p 51820:51820/udp -p 51821:51821/tcp wg-easy"
},
"packageManager": "pnpm@9.6.0"
}
"packageManager": "pnpm@9.7.0"
}

5
src/package.json

@ -28,7 +28,8 @@
"tailwindcss": "^3.4.7",
"timeago.js": "^4.0.2",
"vue": "latest",
"vue3-apexcharts": "^1.5.3"
"vue3-apexcharts": "^1.5.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@nuxt/eslint-config": "^0.5.0",
@ -41,5 +42,5 @@
"typescript": "^5.5.4",
"vue-tsc": "^2.0.29"
},
"packageManager": "pnpm@9.6.0"
"packageManager": "pnpm@9.7.0"
}

11
src/pnpm-lock.yaml

@ -43,6 +43,9 @@ importers:
vue3-apexcharts:
specifier: ^1.5.3
version: 1.5.3([email protected])([email protected]([email protected]))
zod:
specifier: ^3.23.8
version: 3.23.8
devDependencies:
'@nuxt/eslint-config':
specifier: ^0.5.0
@ -7405,6 +7408,12 @@ packages:
}
engines: { node: '>= 14' }
[email protected]:
resolution:
{
integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==,
}
snapshots:
'@alloc/[email protected]': {}
@ -12213,3 +12222,5 @@ snapshots:
archiver-utils: 5.0.2
compress-commons: 6.0.2
readable-stream: 4.5.2
[email protected]: {}

5
src/server/api/session.post.ts

@ -1,6 +1,9 @@
export default defineEventHandler(async (event) => {
const session = await useWGSession(event);
const { password } = await readBody(event);
const { password } = await readValidatedBody(
event,
validateZod(passwordType)
);
if (!REQUIRES_PASSWORD) {
// if no password is required, the API should never be called.

14
src/server/api/wireguard/client/[clientId]/address.put.ts

@ -1,13 +1,9 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
if (
clientId === '__proto__' ||
clientId === 'constructor' ||
clientId === 'prototype'
) {
throw createError({ statusCode: 403 });
}
const { address } = await readBody(event);
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
const { address } = await readValidatedBody(event, validateZod(addressType));
await WireGuard.updateClientAddress({ clientId, address });
return { success: true };
});

5
src/server/api/wireguard/client/[clientId]/configuration.get.ts

@ -1,5 +1,8 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
const client = await WireGuard.getClient({ clientId });
const config = await WireGuard.getClientConfiguration({ clientId });
const configName = client.name

12
src/server/api/wireguard/client/[clientId]/disable.post.ts

@ -1,12 +1,8 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
if (
clientId === '__proto__' ||
clientId === 'constructor' ||
clientId === 'prototype'
) {
throw createError({ statusCode: 403 });
}
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
await WireGuard.disableClient({ clientId });
return { success: true };
});

12
src/server/api/wireguard/client/[clientId]/enable.post.ts

@ -1,12 +1,8 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
if (
clientId === '__proto__' ||
clientId === 'constructor' ||
clientId === 'prototype'
) {
throw createError({ statusCode: 403 });
}
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
await WireGuard.enableClient({ clientId });
return { success: true };
});

5
src/server/api/wireguard/client/[clientId]/index.delete.ts

@ -1,5 +1,8 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
await WireGuard.deleteClient({ clientId });
return { success: true };
});

14
src/server/api/wireguard/client/[clientId]/name.put.ts

@ -1,13 +1,9 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
if (
clientId === '__proto__' ||
clientId === 'constructor' ||
clientId === 'prototype'
) {
throw createError({ statusCode: 403 });
}
const { name } = await readBody(event);
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
const { name } = await readValidatedBody(event, validateZod(nameType));
await WireGuard.updateClientName({ clientId, name });
return { success: true };
});

5
src/server/api/wireguard/client/[clientId]/qrcode.svg.get.ts

@ -1,5 +1,8 @@
export default defineEventHandler(async (event) => {
const clientId = getRouterParam(event, 'clientId');
const { clientId } = await getValidatedRouterParams(
event,
validateZod(clientIdType)
);
const svg = await WireGuard.getClientQRCodeSVG({ clientId });
setHeader(event, 'Content-Type', 'image/svg+xml');
return svg;

2
src/server/api/wireguard/client/index.post.ts

@ -1,5 +1,5 @@
export default defineEventHandler(async (event) => {
const { name } = await readBody(event);
const { name } = await readValidatedBody(event, validateZod(nameType));
await WireGuard.createClient({ name });
return { success: true };
});

2
src/server/api/wireguard/restore.put.ts

@ -1,5 +1,5 @@
export default defineEventHandler(async (event) => {
const { file } = await readBody(event);
const { file } = await readValidatedBody(event, validateZod(fileType));
await WireGuard.restoreConfiguration(file);
return { success: true };
});

65
src/server/utils/types.ts

@ -0,0 +1,65 @@
import type { ZodSchema } from 'zod';
import { z, ZodError } from 'zod';
const safeStringRefine = z
.string()
.refine(
(v) => v !== '__proto__' && v !== 'constructor' && v !== 'prototype',
{ message: 'String is malformed' }
);
const id = z
.string()
.uuid('Client ID must be a valid UUID')
.and(safeStringRefine);
const address = z
.string({ message: 'Address must be a valid string' })
.and(safeStringRefine);
const name = z
.string({ message: 'Name must be a valid string' })
.min(1, 'Name must be at least 1 Character')
.and(safeStringRefine);
const file = z
.string({ message: 'File must be a valid string' })
.and(safeStringRefine);
const password = z
.string({ message: 'Password must be a valid string' })
.and(safeStringRefine);
export const clientIdType = z.object({
clientId: id,
});
export const addressType = z.object({
address: address,
});
export const nameType = z.object({
name: name,
});
export const fileType = z.object({
file: file,
});
export const passwordType = z.object({
password: password,
});
export function validateZod<T>(schema: ZodSchema<T>) {
return async (data: unknown) => {
try {
return await schema.parseAsync(data);
} catch (error) {
let message = 'Unexpected Error';
if (error instanceof ZodError) {
message = error.issues.map((v) => v.message).join('; ');
}
throw new Error(message);
}
};
}
Loading…
Cancel
Save