Implement PBS authentication support for backup discovery
- Add PBSStorageCredential model to database schema (fingerprint now required) - Create PBS credentials API router with CRUD operations - Add PBS login functionality to backup service before discovery - Create PBSCredentialsModal component for managing credentials - Integrate PBS credentials management into ServerStoragesModal - Update storage service to extract PBS IP and datastore info - Add helpful hint about finding fingerprint on PBS dashboard - Auto-accept fingerprint during login using stored credentials
This commit is contained in:
@@ -3,6 +3,7 @@ import { installedScriptsRouter } from "~/server/api/routers/installedScripts";
|
||||
import { serversRouter } from "~/server/api/routers/servers";
|
||||
import { versionRouter } from "~/server/api/routers/version";
|
||||
import { backupsRouter } from "~/server/api/routers/backups";
|
||||
import { pbsCredentialsRouter } from "~/server/api/routers/pbsCredentials";
|
||||
import { createCallerFactory, createTRPCRouter } from "~/server/api/trpc";
|
||||
|
||||
/**
|
||||
@@ -16,6 +17,7 @@ export const appRouter = createTRPCRouter({
|
||||
servers: serversRouter,
|
||||
version: versionRouter,
|
||||
backups: backupsRouter,
|
||||
pbsCredentials: pbsCredentialsRouter,
|
||||
});
|
||||
|
||||
// export type definition of API
|
||||
|
||||
153
src/server/api/routers/pbsCredentials.ts
Normal file
153
src/server/api/routers/pbsCredentials.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { z } from 'zod';
|
||||
import { createTRPCRouter, publicProcedure } from '~/server/api/trpc';
|
||||
import { getDatabase } from '~/server/database-prisma';
|
||||
|
||||
export const pbsCredentialsRouter = createTRPCRouter({
|
||||
// Get credentials for a specific storage
|
||||
getCredentialsForStorage: publicProcedure
|
||||
.input(z.object({
|
||||
serverId: z.number(),
|
||||
storageName: z.string(),
|
||||
}))
|
||||
.query(async ({ input }) => {
|
||||
try {
|
||||
const db = getDatabase();
|
||||
const credential = await db.getPBSCredential(input.serverId, input.storageName);
|
||||
|
||||
if (!credential) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'PBS credentials not found',
|
||||
credential: null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
credential: {
|
||||
id: credential.id,
|
||||
server_id: credential.server_id,
|
||||
storage_name: credential.storage_name,
|
||||
pbs_ip: credential.pbs_ip,
|
||||
pbs_datastore: credential.pbs_datastore,
|
||||
pbs_fingerprint: credential.pbs_fingerprint,
|
||||
// Don't return password for security
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in getCredentialsForStorage:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch PBS credentials',
|
||||
credential: null,
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
// Get all PBS credentials for a server
|
||||
getAllCredentialsForServer: publicProcedure
|
||||
.input(z.object({
|
||||
serverId: z.number(),
|
||||
}))
|
||||
.query(async ({ input }) => {
|
||||
try {
|
||||
const db = getDatabase();
|
||||
const credentials = await db.getPBSCredentialsByServer(input.serverId);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
credentials: credentials.map(c => ({
|
||||
id: c.id,
|
||||
server_id: c.server_id,
|
||||
storage_name: c.storage_name,
|
||||
pbs_ip: c.pbs_ip,
|
||||
pbs_datastore: c.pbs_datastore,
|
||||
pbs_fingerprint: c.pbs_fingerprint,
|
||||
// Don't return password for security
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in getAllCredentialsForServer:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch PBS credentials',
|
||||
credentials: [],
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
// Save/update PBS credentials
|
||||
saveCredentials: publicProcedure
|
||||
.input(z.object({
|
||||
serverId: z.number(),
|
||||
storageName: z.string(),
|
||||
pbs_ip: z.string(),
|
||||
pbs_datastore: z.string(),
|
||||
pbs_password: z.string().optional(), // Optional to allow updating without changing password
|
||||
pbs_fingerprint: z.string(),
|
||||
}))
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const db = getDatabase();
|
||||
|
||||
// If password is not provided, fetch existing credential to preserve password
|
||||
let passwordToSave = input.pbs_password;
|
||||
if (!passwordToSave) {
|
||||
const existing = await db.getPBSCredential(input.serverId, input.storageName);
|
||||
if (existing) {
|
||||
passwordToSave = existing.pbs_password;
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Password is required for new credentials',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
await db.createOrUpdatePBSCredential({
|
||||
server_id: input.serverId,
|
||||
storage_name: input.storageName,
|
||||
pbs_ip: input.pbs_ip,
|
||||
pbs_datastore: input.pbs_datastore,
|
||||
pbs_password: passwordToSave,
|
||||
pbs_fingerprint: input.pbs_fingerprint,
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'PBS credentials saved successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in saveCredentials:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to save PBS credentials',
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
// Delete PBS credentials
|
||||
deleteCredentials: publicProcedure
|
||||
.input(z.object({
|
||||
serverId: z.number(),
|
||||
storageName: z.string(),
|
||||
}))
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const db = getDatabase();
|
||||
await db.deletePBSCredential(input.serverId, input.storageName);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'PBS credentials deleted successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in deleteCredentials:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to delete PBS credentials',
|
||||
};
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user