diff --git a/client/src/javascript/components/auth/AuthForm.tsx b/client/src/javascript/components/auth/AuthForm.tsx index 59227ac3..7542d0b2 100644 --- a/client/src/javascript/components/auth/AuthForm.tsx +++ b/client/src/javascript/components/auth/AuthForm.tsx @@ -1,7 +1,7 @@ import {injectIntl, WrappedComponentProps} from 'react-intl'; import React from 'react'; -import {AccessLevel} from '@shared/schema/Auth'; +import {AccessLevel} from '@shared/schema/constants/Auth'; import type {Credentials} from '@shared/schema/Auth'; diff --git a/client/src/javascript/components/general/connection-settings/ClientConnectionSettingsForm.tsx b/client/src/javascript/components/general/connection-settings/ClientConnectionSettingsForm.tsx index 35d6d18e..94469738 100644 --- a/client/src/javascript/components/general/connection-settings/ClientConnectionSettingsForm.tsx +++ b/client/src/javascript/components/general/connection-settings/ClientConnectionSettingsForm.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {FormattedMessage, injectIntl, WrappedComponentProps} from 'react-intl'; -import {SUPPORTED_CLIENTS} from '@shared/schema/ClientConnectionSettings'; +import {SUPPORTED_CLIENTS} from '@shared/schema/constants/ClientConnectionSettings'; import type {ClientConnectionSettings} from '@shared/schema/ClientConnectionSettings'; diff --git a/client/src/javascript/components/modals/settings-modal/AuthTab.tsx b/client/src/javascript/components/modals/settings-modal/AuthTab.tsx index 34ec55c7..f8f74132 100644 --- a/client/src/javascript/components/modals/settings-modal/AuthTab.tsx +++ b/client/src/javascript/components/modals/settings-modal/AuthTab.tsx @@ -4,7 +4,7 @@ import {FormattedMessage, injectIntl, WrappedComponentProps} from 'react-intl'; import {observer} from 'mobx-react'; import React from 'react'; -import {AccessLevel} from '@shared/schema/Auth'; +import {AccessLevel} from '@shared/schema/constants/Auth'; import type {Credentials} from '@shared/schema/Auth'; import {Button, Checkbox, Form, FormError, FormRowItem, FormRow, LoadingRing, Textbox} from '../../../ui'; diff --git a/client/src/javascript/stores/AuthStore.ts b/client/src/javascript/stores/AuthStore.ts index 7d0cbbc3..31eef40f 100644 --- a/client/src/javascript/stores/AuthStore.ts +++ b/client/src/javascript/stores/AuthStore.ts @@ -1,6 +1,6 @@ import {makeAutoObservable} from 'mobx'; -import {AccessLevel} from '@shared/schema/Auth'; +import {AccessLevel} from '@shared/schema/constants/Auth'; import type {AuthAuthenticationResponse, AuthVerificationResponse} from '@shared/schema/api/auth'; import type {Credentials} from '@shared/schema/Auth'; diff --git a/client/src/javascript/stores/ConfigStore.ts b/client/src/javascript/stores/ConfigStore.ts index 4814b8bf..ed2c9261 100644 --- a/client/src/javascript/stores/ConfigStore.ts +++ b/client/src/javascript/stores/ConfigStore.ts @@ -1,6 +1,6 @@ import {makeAutoObservable} from 'mobx'; -import {AuthVerificationPreloadConfigs} from '@shared/schema/api/auth'; +import type {AuthVerificationPreloadConfigs} from '@shared/schema/api/auth'; class ConfigStore { baseURI = window.location.pathname.substr(0, window.location.pathname.lastIndexOf('/') + 1); diff --git a/server/bin/migrations/UserInDatabase2.ts b/server/bin/migrations/UserInDatabase2.ts index e98d41e3..7522cf59 100644 --- a/server/bin/migrations/UserInDatabase2.ts +++ b/server/bin/migrations/UserInDatabase2.ts @@ -1,4 +1,4 @@ -import {AccessLevel} from '../../../shared/schema/Auth'; +import {AccessLevel} from '../../../shared/schema/constants/Auth'; import Users from '../../models/Users'; import type {Credentials} from '../../../shared/schema/Auth'; diff --git a/server/middleware/requireAdmin.ts b/server/middleware/requireAdmin.ts index eab047a2..8a833976 100644 --- a/server/middleware/requireAdmin.ts +++ b/server/middleware/requireAdmin.ts @@ -1,6 +1,6 @@ import type {Request, Response, NextFunction} from 'express'; -import {AccessLevel} from '../../shared/schema/Auth'; +import {AccessLevel} from '../../shared/schema/constants/Auth'; export default (req: Request, res: Response, next: NextFunction) => { if (req.user == null || req.user.level !== AccessLevel.ADMINISTRATOR) { diff --git a/server/models/Users.ts b/server/models/Users.ts index f4943d9c..4826fbc2 100644 --- a/server/models/Users.ts +++ b/server/models/Users.ts @@ -4,7 +4,7 @@ import Datastore from 'nedb'; import fs from 'fs'; import path from 'path'; -import {AccessLevel} from '../../shared/schema/Auth'; +import {AccessLevel} from '../../shared/schema/constants/Auth'; import type {Credentials, UserInDatabase} from '../../shared/schema/Auth'; diff --git a/server/routes/api/auth.test.ts b/server/routes/api/auth.test.ts index b5fee84b..3ed23c6b 100644 --- a/server/routes/api/auth.test.ts +++ b/server/routes/api/auth.test.ts @@ -1,7 +1,7 @@ import crypto from 'crypto'; import supertest from 'supertest'; -import {AccessLevel} from '../../../shared/schema/Auth'; +import {AccessLevel} from '../../../shared/schema/constants/Auth'; import app from '../../app'; import {getAuthToken} from './auth'; diff --git a/shared/schema/Auth.ts b/shared/schema/Auth.ts index 877a9d5e..c5440a21 100644 --- a/shared/schema/Auth.ts +++ b/shared/schema/Auth.ts @@ -1,19 +1,16 @@ -import * as z from 'zod'; +import {nativeEnum, object, string} from 'zod'; +import type {infer as zodInfer} from 'zod'; +import {AccessLevel} from './constants/Auth'; import {clientConnectionSettingsSchema} from './ClientConnectionSettings'; -export enum AccessLevel { - USER = 5, - ADMINISTRATOR = 10, -} - -export const credentialsSchema = z.object({ - username: z.string(), - password: z.string(), +export const credentialsSchema = object({ + username: string(), + password: string(), client: clientConnectionSettingsSchema, - level: z.nativeEnum(AccessLevel), + level: nativeEnum(AccessLevel), }); -export type Credentials = z.infer; +export type Credentials = zodInfer; export type UserInDatabase = Required & {_id: string}; diff --git a/shared/schema/ClientConnectionSettings.ts b/shared/schema/ClientConnectionSettings.ts index b63d3645..1e043353 100644 --- a/shared/schema/ClientConnectionSettings.ts +++ b/shared/schema/ClientConnectionSettings.ts @@ -1,68 +1,67 @@ -import * as z from 'zod'; +import {literal, number, object, string, union} from 'zod'; +import type {infer as zodInfer} from 'zod'; -const delugeConnectionSettingsSchema = z.object({ - client: z.literal('Deluge'), - type: z.literal('web'), - version: z.literal(1), - url: z.string().url(), - password: z.string(), +const delugeConnectionSettingsSchema = object({ + client: literal('Deluge'), + type: literal('web'), + version: literal(1), + url: string().url(), + password: string(), }); -export type DelugeConnectionSettings = z.infer; +export type DelugeConnectionSettings = zodInfer; -const qBittorrentConnectionSettingsSchema = z.object({ - client: z.literal('qBittorrent'), - type: z.literal('web'), - version: z.literal(1), - url: z.string().url(), - username: z.string(), - password: z.string(), +const qBittorrentConnectionSettingsSchema = object({ + client: literal('qBittorrent'), + type: literal('web'), + version: literal(1), + url: string().url(), + username: string(), + password: string(), }); -export type QBittorrentConnectionSettings = z.infer; +export type QBittorrentConnectionSettings = zodInfer; -const rTorrentTCPConnectionSettingsSchema = z.object({ - client: z.literal('rTorrent'), - type: z.literal('tcp'), - version: z.literal(1), - host: z.string(), - port: z.number(), +const rTorrentTCPConnectionSettingsSchema = object({ + client: literal('rTorrent'), + type: literal('tcp'), + version: literal(1), + host: string(), + port: number(), }); -export type RTorrentTCPConnectionSettings = z.infer; +export type RTorrentTCPConnectionSettings = zodInfer; -const rTorrentSocketConnectionSettingsSchema = z.object({ - client: z.literal('rTorrent'), - type: z.literal('socket'), - version: z.literal(1), - socket: z.string(), +const rTorrentSocketConnectionSettingsSchema = object({ + client: literal('rTorrent'), + type: literal('socket'), + version: literal(1), + socket: string(), }); -export type RTorrentSocketConnectionSettings = z.infer; +export type RTorrentSocketConnectionSettings = zodInfer; -const rTorrentConnectionSettingsSchema = z.union([ +const rTorrentConnectionSettingsSchema = union([ rTorrentTCPConnectionSettingsSchema, rTorrentSocketConnectionSettingsSchema, ]); -export type RTorrentConnectionSettings = z.infer; +export type RTorrentConnectionSettings = zodInfer; -const transmissionConnectionSettingsSchema = z.object({ - client: z.literal('Transmission'), - type: z.literal('web'), - version: z.literal(1), - url: z.string().url(), - username: z.string(), - password: z.string(), +const transmissionConnectionSettingsSchema = object({ + client: literal('Transmission'), + type: literal('web'), + version: literal(1), + url: string().url(), + username: string(), + password: string(), }); -export type TransmissionConnectionSettings = z.infer; +export type TransmissionConnectionSettings = zodInfer; -export const clientConnectionSettingsSchema = z.union([ +export const clientConnectionSettingsSchema = union([ qBittorrentConnectionSettingsSchema, rTorrentConnectionSettingsSchema, ]); -export type ClientConnectionSettings = z.infer; - -export const SUPPORTED_CLIENTS: Array = ['qBittorrent', 'rTorrent']; +export type ClientConnectionSettings = zodInfer; diff --git a/shared/schema/api/auth.ts b/shared/schema/api/auth.ts index f90fa4af..627b170e 100644 --- a/shared/schema/api/auth.ts +++ b/shared/schema/api/auth.ts @@ -1,12 +1,13 @@ -import * as z from 'zod'; +import type {infer as zodInfer} from 'zod'; -import {AccessLevel, credentialsSchema} from '../Auth'; +import {AccessLevel} from '../constants/Auth'; +import {credentialsSchema} from '../Auth'; // All auth requests are schema validated to ensure security. // POST /api/auth/authenticate export const authAuthenticationSchema = credentialsSchema.pick({username: true, password: true}); -export type AuthAuthenticationOptions = Required>; +export type AuthAuthenticationOptions = Required>; // POST /api/auth/authenticate - success response export interface AuthAuthenticationResponse { @@ -17,11 +18,11 @@ export interface AuthAuthenticationResponse { // POST /api/auth/register export const authRegistrationSchema = credentialsSchema; -export type AuthRegistrationOptions = Required>; +export type AuthRegistrationOptions = Required>; // PATCH /api/auth/users/{username} export const authUpdateUserSchema = credentialsSchema.partial(); -export type AuthUpdateUserOptions = z.infer; +export type AuthUpdateUserOptions = zodInfer; // GET /api/auth/verify - preload configurations export interface AuthVerificationPreloadConfigs { diff --git a/shared/schema/constants/Auth.ts b/shared/schema/constants/Auth.ts new file mode 100644 index 00000000..a6614296 --- /dev/null +++ b/shared/schema/constants/Auth.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line import/prefer-default-export +export enum AccessLevel { + USER = 5, + ADMINISTRATOR = 10, +} diff --git a/shared/schema/constants/ClientConnectionSettings.ts b/shared/schema/constants/ClientConnectionSettings.ts new file mode 100644 index 00000000..2006de87 --- /dev/null +++ b/shared/schema/constants/ClientConnectionSettings.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/prefer-default-export +export const SUPPORTED_CLIENTS = ['qBittorrent', 'rTorrent'] as const;