<!---
  Authenticated download for internal-only folders (public HTTP is blocked by .htaccess).
  Requires login via __Security-Block.cfm.

  Examples:
    /agencyadmin/datafile_download.cfm?file=123.dat
    /agencyadmin/datafile_download.cfm?dir=xmlfilecreation&file=agency_123.xml
    /agencyadmin/datafile_download.cfm?dir=faxfiles&file=20260918010924.pdf
--->
<cfinclude template="../__Security-Block.cfm" />

<cfparam name="url.file" default="" />
<cfparam name="url.dir" default="datafiles" />

<!--- Whitelist of internal folders only --->
<cfset LOCAL.bases = structNew() />
<cfset LOCAL.bases["datafiles"] = "/var/www/datafiles/" />
<cfset LOCAL.bases["xmlfilecreation"] = "/var/www/xmlfilecreation/" />
<cfset LOCAL.bases["faxfiles"] = "/var/www/faxfiles/" />
<cfset LOCAL.bases["claimfiles"] = "/var/www/claimfiles/" />
<cfset LOCAL.bases["upload"] = "/var/www/Upload/" />
<cfset LOCAL.bases["inovalon_files"] = "/var/www/Inovalon_files/" />
<cfset LOCAL.bases["xmlfiles"] = "/var/www/XMLfiles/" />
<cfset LOCAL.bases["medicationfiles"] = "/var/www/Medicationfiles/" />
<cfset LOCAL.bases["csv"] = "/var/www/managementreports/CSV/" />

<cfset LOCAL.dirKey = lCase(trim(url.dir)) />
<cfif NOT structKeyExists(LOCAL.bases, LOCAL.dirKey)>
	<cfheader statuscode="400" statustext="Bad Request" />
	<cfoutput>Invalid directory.</cfoutput>
	<cfabort />
</cfif>
<cfset LOCAL.basePath = LOCAL.bases[LOCAL.dirKey] />

<cfset LOCAL.safeName = trim(url.file) />
<!--- CF may leave + for spaces depending on client encoding --->
<cfset LOCAL.safeName = replace(LOCAL.safeName, "+", " ", "all") />
<cfset LOCAL.safeName = listLast(replace(LOCAL.safeName, "\", "/", "all"), "/") />
<!--- Allow spaces and common safe filename chars; block path separators / traversal --->
<cfset LOCAL.safeName = reReplace(LOCAL.safeName, "[^A-Za-z0-9._\- ()]", "", "all") />
<cfset LOCAL.safeName = trim(LOCAL.safeName) />

<cfif NOT len(LOCAL.safeName)>
	<cfheader statuscode="400" statustext="Bad Request" />
	<cfoutput>Invalid file request.</cfoutput>
	<cfabort />
</cfif>

<cfset LOCAL.ext = lCase(listLast(LOCAL.safeName, ".")) />
<cfset LOCAL.allowedExt = "dat,csv,xlsx,xls,txt,837,zip,xml,pdf,json" />
<cfif NOT listFindNoCase(LOCAL.allowedExt, LOCAL.ext)>
	<cfheader statuscode="400" statustext="Bad Request" />
	<cfoutput>File type not allowed.</cfoutput>
	<cfabort />
</cfif>

<cfset LOCAL.fullPath = LOCAL.basePath & LOCAL.safeName />

<cfif NOT fileExists(LOCAL.fullPath)>
	<cfheader statuscode="404" statustext="Not Found" />
	<cfoutput>The requested file was not found.</cfoutput>
	<cfabort />
</cfif>

<cfset LOCAL.resolved = getFileInfo(LOCAL.fullPath).path />
<cfif left(LOCAL.resolved, len(LOCAL.basePath)) NEQ LOCAL.basePath>
	<cfheader statuscode="403" statustext="Forbidden" />
	<cfoutput>Access denied.</cfoutput>
	<cfabort />
</cfif>

<cfswitch expression="#LOCAL.ext#">
	<cfcase value="csv">
		<cfset LOCAL.mime = "text/csv" />
	</cfcase>
	<cfcase value="xlsx">
		<cfset LOCAL.mime = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
	</cfcase>
	<cfcase value="xls">
		<cfset LOCAL.mime = "application/vnd.ms-excel" />
	</cfcase>
	<cfcase value="zip">
		<cfset LOCAL.mime = "application/zip" />
	</cfcase>
	<cfcase value="xml">
		<cfset LOCAL.mime = "application/xml" />
	</cfcase>
	<cfcase value="pdf">
		<cfset LOCAL.mime = "application/pdf" />
	</cfcase>
	<cfcase value="json">
		<cfset LOCAL.mime = "application/json" />
	</cfcase>
	<cfdefaultcase>
		<cfset LOCAL.mime = "application/octet-stream" />
	</cfdefaultcase>
</cfswitch>

<cfheader name="Content-Disposition" value="attachment; filename=#LOCAL.safeName#" />
<cfheader name="X-Content-Type-Options" value="nosniff" />
<cfcontent type="#LOCAL.mime#" file="#LOCAL.fullPath#" deletefile="no" />
