Skip to content

Commit

Permalink
Handle URL paths better (cross-seed#514)
Browse files Browse the repository at this point in the history
added a `basePath` argument to `extractCredentialsFromURL` that should
hopefully prevent us from making the same mistake I made again.

```js
> extractCredentialsFromUrl('http://admin:adminadmin@localhost:8080/qbit')
OkResult {
  contents: {
    username: 'admin',
    password: 'adminadmin',
    href: 'http://localhost:8080/qbit'
  }
}
> extractCredentialsFromUrl('http://admin:adminadmin@localhost:8080')
OkResult {
  contents: {
    username: 'admin',
    password: 'adminadmin',
    href: 'http://localhost:8080'
  }
}
> extractCredentialsFromUrl('http://admin:adminadmin@localhost:8080/qbit', '/api/v2')
OkResult {
  contents: {
    username: 'admin',
    password: 'adminadmin',
    href: 'http://localhost:8080/qbit/api/v2'
  }
}
> extractCredentialsFromUrl('http://admin:adminadmin@localhost:8080', '/api/v2')
OkResult {
  contents: {
    username: 'admin',
    password: 'adminadmin',
    href: 'http://localhost:8080/api/v2'
  }
}
```

---------

Co-authored-by: zakary <[email protected]>
  • Loading branch information
mmgoodnow and zakkarry authored Oct 6, 2023
1 parent 427546b commit 0cdbb23
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 11 deletions.
19 changes: 11 additions & 8 deletions src/clients/QBittorrent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,23 @@ interface Category {

export default class QBittorrent implements TorrentClient {
cookie: string;
url: { username: string; password: string; href: string };

async login(): Promise<void> {
constructor() {
const { qbittorrentUrl } = getRuntimeConfig();
const { username, password, href } = extractCredentialsFromUrl(
qbittorrentUrl
this.url = extractCredentialsFromUrl(
qbittorrentUrl,
"/api/v2"
).unwrapOrThrow(
new CrossSeedError("qBittorrent url must be percent-encoded")
);
}

async login(): Promise<void> {
let response: Response;
const { href, username, password } = this.url;
try {
response = await fetch(`${href}api/v2/auth/login`, {
response = await fetch(`${href}/auth/login`, {
method: "POST",
body: new URLSearchParams({ username, password }),
});
Expand Down Expand Up @@ -137,10 +142,8 @@ export default class QBittorrent implements TorrentClient {
label: Label.QBITTORRENT,
message: `Making request to ${path} with body ${body.toString()}`,
});
const { qbittorrentUrl } = getRuntimeConfig();
const { href } =
extractCredentialsFromUrl(qbittorrentUrl).unwrapOrThrow();
const response = await fetch(`${href}api/v2${path}`, {

const response = await fetch(`${this.url.href}${path}`, {
method: "post",
headers: { Cookie: this.cookie, ...headers },
body,
Expand Down
11 changes: 8 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { basename } from "path";
import path, { basename, join } from "path";
import {
EP_REGEX,
MOVIE_REGEX,
Expand Down Expand Up @@ -96,14 +96,19 @@ export function fallback<T>(...args: T[]): T {
}

export function extractCredentialsFromUrl(
url: string
url: string,
basePath?: string
): Result<{ username: string; password: string; href: string }, "invalid URL"> {
try {
const { origin, pathname, username, password } = new URL(url);
return resultOf({
username: decodeURIComponent(username),
password: decodeURIComponent(password),
href: origin + pathname,
href: basePath
? origin + path.posix.join(pathname, basePath)
: pathname === "/"
? origin
: origin + pathname,
});
} catch (e) {
return resultOfErr("invalid URL");
Expand Down

0 comments on commit 0cdbb23

Please sign in to comment.