auth, Users: initial preparation for multi client support

BREAKING CHANGE
This commit is contained in:
Jesse Chan
2020-10-11 00:07:11 +08:00
parent 61002f698b
commit cf08d68c92
35 changed files with 878 additions and 504 deletions
+19
View File
@@ -0,0 +1,19 @@
import * as z from 'zod';
import {clientConnectionSettingsSchema} from './ClientConnectionSettings';
export enum AccessLevel {
USER = 5,
ADMINISTRATOR = 10,
}
export const credentialsSchema = z.object({
username: z.string(),
password: z.string(),
client: clientConnectionSettingsSchema,
level: z.nativeEnum(AccessLevel),
});
export type Credentials = z.infer<typeof credentialsSchema>;
export type UserInDatabase = Required<Credentials> & {_id: string};
+63
View File
@@ -0,0 +1,63 @@
import * as z 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(),
});
export type DelugeConnectionSettings = z.infer<typeof delugeConnectionSettingsSchema>;
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(),
});
export type QBittorrentConnectionSettings = z.infer<typeof qBittorrentConnectionSettingsSchema>;
const rTorrentTCPConnectionSettingsSchema = z.object({
client: z.literal('rTorrent'),
type: z.literal('tcp'),
version: z.literal(1),
host: z.string(),
port: z.number(),
});
export type RTorrentTCPConnectionSettings = z.infer<typeof rTorrentTCPConnectionSettingsSchema>;
const rTorrentSocketConnectionSettingsSchema = z.object({
client: z.literal('rTorrent'),
type: z.literal('socket'),
version: z.literal(1),
socket: z.string(),
});
export type RTorrentSocketConnectionSettings = z.infer<typeof rTorrentSocketConnectionSettingsSchema>;
const rTorrentConnectionSettingsSchema = z.union([
rTorrentTCPConnectionSettingsSchema,
rTorrentSocketConnectionSettingsSchema,
]);
export type RTorrentConnectionSettings = z.infer<typeof rTorrentConnectionSettingsSchema>;
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(),
});
export type TransmissionConnectionSettings = z.infer<typeof transmissionConnectionSettingsSchema>;
export const clientConnectionSettingsSchema = rTorrentConnectionSettingsSchema;
export type ClientConnectionSettings = z.infer<typeof clientConnectionSettingsSchema>;
+37
View File
@@ -0,0 +1,37 @@
import * as z from 'zod';
import {AccessLevel, 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<z.infer<typeof authAuthenticationSchema>>;
// POST /api/auth/authenticate - success response
export interface AuthAuthenticationResponse {
success: boolean;
token: string;
username: string;
level: AccessLevel;
}
// POST /api/auth/register
export const authRegistrationSchema = credentialsSchema;
export type AuthRegistrationOptions = Required<z.infer<typeof authRegistrationSchema>>;
// PATCH /api/auth/users/{username}
export const authUpdateUserSchema = credentialsSchema.partial();
export type AuthUpdateUserOptions = z.infer<typeof authUpdateUserSchema>;
// GET /api/auth/verify - success response
export type AuthVerificationResponse =
| {
initialUser: true;
}
| {
initialUser: false;
username: string;
level: AccessLevel;
token?: string;
};
-17
View File
@@ -1,17 +0,0 @@
export interface ConnectionSettingsForm {
connectionType?: 'socket' | 'tcp';
rtorrentSocketPath?: string;
rtorrentPort?: number;
rtorrentHost?: string;
}
export interface Credentials {
username: string;
password?: string;
host?: string | null;
port?: number | null;
socketPath?: string | null;
isAdmin?: boolean;
}
export type UserInDatabase = Required<Credentials> & {_id: string};
-27
View File
@@ -1,27 +0,0 @@
import type {Credentials} from '../Auth';
// POST /api/auth/authenticate
export type AuthAuthenticationOptions = Required<Pick<Credentials, 'username' | 'password'>>;
// POST /api/auth/authenticate - success response
export interface AuthAuthenticationResponse {
success: boolean;
token: string;
username: string;
isAdmin: boolean;
}
// POST /api/auth/register
export type AuthRegisterOptions = Required<
Pick<Credentials, 'username' | 'password' | 'host' | 'port' | 'socketPath' | 'isAdmin'>
>;
// PATCH /api/auth/users/{username}
export type AuthUpdateUserOptions = Partial<Credentials>;
// GET /api/auth/verify - success response
export interface AuthVerificationResponse extends Pick<AuthAuthenticationResponse, 'token'> {
initialUser: boolean;
username: string;
isAdmin: boolean;
}