fix: classify invalid subsonic URL as unreachable, type settings handlers, guard token mask and body types
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { FastifyInstance } from 'fastify'
|
import { FastifyInstance } from 'fastify'
|
||||||
import { SubsonicClient } from '../subsonic.js'
|
import { SubsonicClient } from '../subsonic.js'
|
||||||
import { requireAuth } from './authRoutes.js'
|
import { requireAuth } from './authRoutes.js'
|
||||||
|
import type { UserRow } from '../auth.js'
|
||||||
import type { DB } from '../db.js'
|
import type { DB } from '../db.js'
|
||||||
|
|
||||||
export interface SettingsRow {
|
export interface SettingsRow {
|
||||||
@@ -23,7 +24,11 @@ export function getSettings(db: DB, userId: number): SettingsRow {
|
|||||||
export function settingsView(s: SettingsRow) {
|
export function settingsView(s: SettingsRow) {
|
||||||
return {
|
return {
|
||||||
hasDiscogsToken: !!s.discogs_token,
|
hasDiscogsToken: !!s.discogs_token,
|
||||||
discogsTokenMasked: s.discogs_token ? `****${s.discogs_token.slice(-5)}` : null,
|
discogsTokenMasked: s.discogs_token
|
||||||
|
? s.discogs_token.length > 5
|
||||||
|
? `****${s.discogs_token.slice(-5)}`
|
||||||
|
: '****'
|
||||||
|
: null,
|
||||||
subsonicUrl: s.subsonic_url,
|
subsonicUrl: s.subsonic_url,
|
||||||
subsonicUsername: s.subsonic_username,
|
subsonicUsername: s.subsonic_username,
|
||||||
hasSubsonicPassword: !!s.subsonic_password,
|
hasSubsonicPassword: !!s.subsonic_password,
|
||||||
@@ -36,15 +41,20 @@ export function subsonicConfigComplete(s: SettingsRow): boolean {
|
|||||||
|
|
||||||
export async function registerSettingsRoutes(app: FastifyInstance): Promise<void> {
|
export async function registerSettingsRoutes(app: FastifyInstance): Promise<void> {
|
||||||
app.get('/api/settings', { preHandler: [requireAuth] }, async (request) => {
|
app.get('/api/settings', { preHandler: [requireAuth] }, async (request) => {
|
||||||
const s = getSettings(request.server.db, (request.user as any).id)
|
const s = getSettings(request.server.db, (request.user as UserRow).id)
|
||||||
return settingsView(s)
|
return settingsView(s)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.put('/api/settings', { preHandler: [requireAuth] }, async (request, reply) => {
|
app.put('/api/settings', { preHandler: [requireAuth] }, async (request, reply) => {
|
||||||
const db = request.server.db
|
const db = request.server.db
|
||||||
const userId = (request.user as any).id
|
const userId = (request.user as UserRow).id
|
||||||
const s = getSettings(db, userId)
|
const s = getSettings(db, userId)
|
||||||
const body = (request.body ?? {}) as Record<string, string | undefined>
|
const body = (request.body ?? {}) as Record<string, string | undefined>
|
||||||
|
for (const value of Object.values(body)) {
|
||||||
|
if (value !== undefined && typeof value !== 'string') {
|
||||||
|
return reply.code(400).send({ error: 'invalid_input', detail: 'settings fields must be strings' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const next = {
|
const next = {
|
||||||
discogs_token: body.discogsToken !== undefined ? body.discogsToken || null : s.discogs_token,
|
discogs_token: body.discogsToken !== undefined ? body.discogsToken || null : s.discogs_token,
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ export class SubsonicClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async request(endpoint: string, params: Record<string, string> = {}): Promise<any> {
|
private async request(endpoint: string, params: Record<string, string> = {}): Promise<any> {
|
||||||
|
let res: Response
|
||||||
|
try {
|
||||||
const url = new URL(`${this.base}/rest/${endpoint}`)
|
const url = new URL(`${this.base}/rest/${endpoint}`)
|
||||||
const search = { ...this.authParams(), ...params }
|
const search = { ...this.authParams(), ...params }
|
||||||
for (const [k, v] of Object.entries(search)) url.searchParams.set(k, v)
|
for (const [k, v] of Object.entries(search)) url.searchParams.set(k, v)
|
||||||
let res: Response
|
|
||||||
try {
|
|
||||||
res = await this.fetchImpl(url.toString())
|
res = await this.fetchImpl(url.toString())
|
||||||
} catch {
|
} catch {
|
||||||
throw new SubsonicError('unreachable', `could not reach ${this.base}`)
|
throw new SubsonicError('unreachable', `could not reach ${this.base}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user