2022-11-29 20:11:50 -08:00
import { formatApiCall } from "utils/proxy/api-helpers" ;
import { httpProxy } from "utils/proxy/http" ;
import createLogger from "utils/logger" ;
import widgets from "widgets/widgets" ;
import getServiceWidget from "utils/config/service-helpers" ;
2022-12-22 10:54:03 -08:00
const logger = createLogger ( "downloadstationProxyHandler" ) ;
2022-11-29 20:11:50 -08:00
2023-01-03 15:51:21 -08:00
async function login ( loginUrl ) {
2022-11-29 20:11:50 -08:00
const [ status , contentType , data ] = await httpProxy ( loginUrl ) ;
if ( status !== 200 ) {
return [ status , contentType , data ] ;
}
const json = JSON . parse ( data . toString ( ) ) ;
if ( json ? . success !== true ) {
// from https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/DownloadStation/All/enu/Synology_Download_Station_Web_API.pdf
/ *
Code Description
400 No such account or incorrect password
401 Account disabled
402 Permission denied
403 2 - step verification code required
404 Failed to authenticate 2 - step verification code
* /
let message = "Authentication failed." ;
if ( json ? . error ? . code >= 403 ) message += " 2FA enabled." ;
logger . warn ( "Unable to login. Code: %d" , json ? . error ? . code ) ;
return [ 401 , "application/json" , JSON . stringify ( { code : json ? . error ? . code , message } ) ] ;
}
return [ status , contentType , data ] ;
}
2022-12-22 10:54:03 -08:00
export default async function downloadstationProxyHandler ( req , res ) {
2022-11-29 20:11:50 -08:00
const { group , service , endpoint } = req . query ;
if ( ! group || ! service ) {
return res . status ( 400 ) . json ( { error : "Invalid proxy service type" } ) ;
}
const widget = await getServiceWidget ( group , service ) ;
const api = widgets ? . [ widget . type ] ? . api ;
if ( ! api ) {
return res . status ( 403 ) . json ( { error : "Service does not support API calls" } ) ;
}
const url = formatApiCall ( api , { endpoint , ... widget } ) ;
let [ status , contentType , data ] = await httpProxy ( url ) ;
if ( status !== 200 ) {
logger . debug ( "Error %d calling endpoint %s" , status , url ) ;
return res . status ( status , data ) ;
}
const json = JSON . parse ( data . toString ( ) ) ;
if ( json ? . success !== true ) {
2023-01-03 15:51:21 -08:00
logger . debug ( "Attempting login to DownloadStation" ) ;
const apiInfoUrl = formatApiCall ( "{url}/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query" , widget ) ;
let path = "entry.cgi" ;
let maxVersion = 7 ;
[ status , contentType , data ] = await httpProxy ( apiInfoUrl ) ;
if ( status === 200 ) {
try {
const apiAuthInfo = JSON . parse ( data . toString ( ) ) . data [ 'SYNO.API.Auth' ] ;
if ( apiAuthInfo ) {
path = apiAuthInfo . path ;
maxVersion = apiAuthInfo . maxVersion ;
logger . debug ( ` Deteceted Downloadstation auth API path: ${ path } and maxVersion: ${ maxVersion } ` ) ;
}
} catch {
logger . debug ( ` Error ${ status } obtaining DownloadStation API info ` ) ;
}
}
const authApi = ` {url}/webapi/ ${ path } ?api=SYNO.API.Auth&version= ${ maxVersion } &method=login&account={username}&passwd={password}&session=DownloadStation&format=cookie `
const loginUrl = formatApiCall ( authApi , widget ) ;
[ status , contentType , data ] = await login ( loginUrl ) ;
2022-11-29 20:11:50 -08:00
if ( status !== 200 ) {
return res . status ( status ) . end ( data )
}
[ status , contentType , data ] = await httpProxy ( url ) ;
}
if ( contentType ) res . setHeader ( "Content-Type" , contentType ) ;
return res . status ( status ) . send ( data ) ;
}