feat(certificates): handle self signed certificates (#1951)
* wip: add page and loading of certificates in folder * wip: add certificate addition and removal * feat: add removal ui for certificates * feat: migrate integrations to fetch or agent with trusted certificates * fix: lock file issues * fix: typecheck issue * fix: inconsistent package versions * chore: address pull request feedback * fix: add missing navigation item and restrict access to page * chore: address pull request feedback * fix: inconsistent undici dependency version * fix: inconsistent undici dependency version
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { Deluge } from "@ctrl/deluge";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { createCertificateAgentAsync } from "@homarr/certificates/server";
|
||||
|
||||
import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data";
|
||||
import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration";
|
||||
import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items";
|
||||
@@ -8,13 +10,13 @@ import type { DownloadClientStatus } from "../../interfaces/downloads/download-c
|
||||
|
||||
export class DelugeIntegration extends DownloadClientIntegration {
|
||||
public async testConnectionAsync(): Promise<void> {
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
await client.login();
|
||||
}
|
||||
|
||||
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> {
|
||||
const type = "torrent";
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const {
|
||||
stats: { download_rate, upload_rate },
|
||||
torrents: rawTorrents,
|
||||
@@ -57,7 +59,7 @@ export class DelugeIntegration extends DownloadClientIntegration {
|
||||
}
|
||||
|
||||
public async pauseQueueAsync() {
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const store = (await client.listTorrents()).result.torrents;
|
||||
await Promise.all(
|
||||
Object.entries(store).map(async ([id]) => {
|
||||
@@ -67,11 +69,12 @@ export class DelugeIntegration extends DownloadClientIntegration {
|
||||
}
|
||||
|
||||
public async pauseItemAsync({ id }: DownloadClientItem): Promise<void> {
|
||||
await this.getClient().pauseTorrent(id);
|
||||
const client = await this.getClientAsync();
|
||||
await client.pauseTorrent(id);
|
||||
}
|
||||
|
||||
public async resumeQueueAsync() {
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const store = (await client.listTorrents()).result.torrents;
|
||||
await Promise.all(
|
||||
Object.entries(store).map(async ([id]) => {
|
||||
@@ -81,17 +84,20 @@ export class DelugeIntegration extends DownloadClientIntegration {
|
||||
}
|
||||
|
||||
public async resumeItemAsync({ id }: DownloadClientItem): Promise<void> {
|
||||
await this.getClient().resumeTorrent(id);
|
||||
const client = await this.getClientAsync();
|
||||
await client.resumeTorrent(id);
|
||||
}
|
||||
|
||||
public async deleteItemAsync({ id }: DownloadClientItem, fromDisk: boolean): Promise<void> {
|
||||
await this.getClient().removeTorrent(id, fromDisk);
|
||||
const client = await this.getClientAsync();
|
||||
await client.removeTorrent(id, fromDisk);
|
||||
}
|
||||
|
||||
private getClient() {
|
||||
private async getClientAsync() {
|
||||
return new Deluge({
|
||||
baseUrl: this.url("/").toString(),
|
||||
password: this.getSecretValue("password"),
|
||||
dispatcher: await createCertificateAgentAsync(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
|
||||
|
||||
import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data";
|
||||
import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration";
|
||||
import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items";
|
||||
@@ -96,7 +98,7 @@ export class NzbGetIntegration extends DownloadClientIntegration {
|
||||
const password = this.getSecretValue("password");
|
||||
const url = this.url(`/${username}:${password}/jsonrpc`);
|
||||
const body = JSON.stringify({ method, params });
|
||||
return await fetch(url, { method: "POST", body })
|
||||
return await fetchWithTrustedCertificatesAsync(url, { method: "POST", body })
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { QBittorrent } from "@ctrl/qbittorrent";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { createCertificateAgentAsync } from "@homarr/certificates/server";
|
||||
|
||||
import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data";
|
||||
import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration";
|
||||
import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items";
|
||||
@@ -8,13 +10,13 @@ import type { DownloadClientStatus } from "../../interfaces/downloads/download-c
|
||||
|
||||
export class QBitTorrentIntegration extends DownloadClientIntegration {
|
||||
public async testConnectionAsync(): Promise<void> {
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
await client.login();
|
||||
}
|
||||
|
||||
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> {
|
||||
const type = "torrent";
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const torrents = await client.listTorrents();
|
||||
const rates = torrents.reduce(
|
||||
({ down, up }, { dlspeed, upspeed }) => ({ down: down + dlspeed, up: up + upspeed }),
|
||||
@@ -50,30 +52,36 @@ export class QBitTorrentIntegration extends DownloadClientIntegration {
|
||||
}
|
||||
|
||||
public async pauseQueueAsync() {
|
||||
await this.getClient().pauseTorrent("all");
|
||||
const client = await this.getClientAsync();
|
||||
await client.pauseTorrent("all");
|
||||
}
|
||||
|
||||
public async pauseItemAsync({ id }: DownloadClientItem): Promise<void> {
|
||||
await this.getClient().pauseTorrent(id);
|
||||
const client = await this.getClientAsync();
|
||||
await client.pauseTorrent(id);
|
||||
}
|
||||
|
||||
public async resumeQueueAsync() {
|
||||
await this.getClient().resumeTorrent("all");
|
||||
const client = await this.getClientAsync();
|
||||
await client.resumeTorrent("all");
|
||||
}
|
||||
|
||||
public async resumeItemAsync({ id }: DownloadClientItem): Promise<void> {
|
||||
await this.getClient().resumeTorrent(id);
|
||||
const client = await this.getClientAsync();
|
||||
await client.resumeTorrent(id);
|
||||
}
|
||||
|
||||
public async deleteItemAsync({ id }: DownloadClientItem, fromDisk: boolean): Promise<void> {
|
||||
await this.getClient().removeTorrent(id, fromDisk);
|
||||
const client = await this.getClientAsync();
|
||||
await client.removeTorrent(id, fromDisk);
|
||||
}
|
||||
|
||||
private getClient() {
|
||||
private async getClientAsync() {
|
||||
return new QBittorrent({
|
||||
baseUrl: this.url("/").toString(),
|
||||
username: this.getSecretValue("username"),
|
||||
password: this.getSecretValue("password"),
|
||||
dispatcher: await createCertificateAgentAsync(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import dayjs from "dayjs";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
|
||||
|
||||
import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data";
|
||||
import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration";
|
||||
import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items";
|
||||
@@ -106,12 +108,12 @@ export class SabnzbdIntegration extends DownloadClientIntegration {
|
||||
apikey: this.getSecretValue("apiKey"),
|
||||
});
|
||||
|
||||
return await fetch(url)
|
||||
return await fetchWithTrustedCertificatesAsync(url)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
return response.json() as Promise<unknown>;
|
||||
return response.json();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error instanceof Error) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Transmission } from "@ctrl/transmission";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { createCertificateAgentAsync } from "@homarr/certificates/server";
|
||||
|
||||
import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data";
|
||||
import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration";
|
||||
import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items";
|
||||
@@ -8,12 +10,13 @@ import type { DownloadClientStatus } from "../../interfaces/downloads/download-c
|
||||
|
||||
export class TransmissionIntegration extends DownloadClientIntegration {
|
||||
public async testConnectionAsync(): Promise<void> {
|
||||
await this.getClient().getSession();
|
||||
const client = await this.getClientAsync();
|
||||
await client.getSession();
|
||||
}
|
||||
|
||||
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> {
|
||||
const type = "torrent";
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const { torrents } = (await client.listTorrents()).arguments;
|
||||
const rates = torrents.reduce(
|
||||
({ down, up }, { rateDownload, rateUpload }) => ({ down: down + rateDownload, up: up + rateUpload }),
|
||||
@@ -47,34 +50,38 @@ export class TransmissionIntegration extends DownloadClientIntegration {
|
||||
}
|
||||
|
||||
public async pauseQueueAsync() {
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const ids = (await client.listTorrents()).arguments.torrents.map(({ hashString }) => hashString);
|
||||
await this.getClient().pauseTorrent(ids);
|
||||
await client.pauseTorrent(ids);
|
||||
}
|
||||
|
||||
public async pauseItemAsync({ id }: DownloadClientItem): Promise<void> {
|
||||
await this.getClient().pauseTorrent(id);
|
||||
const client = await this.getClientAsync();
|
||||
await client.pauseTorrent(id);
|
||||
}
|
||||
|
||||
public async resumeQueueAsync() {
|
||||
const client = this.getClient();
|
||||
const client = await this.getClientAsync();
|
||||
const ids = (await client.listTorrents()).arguments.torrents.map(({ hashString }) => hashString);
|
||||
await this.getClient().resumeTorrent(ids);
|
||||
await client.resumeTorrent(ids);
|
||||
}
|
||||
|
||||
public async resumeItemAsync({ id }: DownloadClientItem): Promise<void> {
|
||||
await this.getClient().resumeTorrent(id);
|
||||
const client = await this.getClientAsync();
|
||||
await client.resumeTorrent(id);
|
||||
}
|
||||
|
||||
public async deleteItemAsync({ id }: DownloadClientItem, fromDisk: boolean): Promise<void> {
|
||||
await this.getClient().removeTorrent(id, fromDisk);
|
||||
const client = await this.getClientAsync();
|
||||
await client.removeTorrent(id, fromDisk);
|
||||
}
|
||||
|
||||
private getClient() {
|
||||
private async getClientAsync() {
|
||||
return new Transmission({
|
||||
baseUrl: this.url("/").toString(),
|
||||
username: this.getSecretValue("username"),
|
||||
password: this.getSecretValue("password"),
|
||||
dispatcher: await createCertificateAgentAsync(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user