48 lines
3.9 KiB
JavaScript
48 lines
3.9 KiB
JavaScript
'use strict';
|
|
const fs=require('node:fs');
|
|
const {createHash}=require('node:crypto');
|
|
const {detectType,inspectFileTransfer}=require('../../packages/core/file-transfer.cjs');
|
|
const CHANNELS={upload:'scanUploads',download:'scanDownloads',clipboard:'scanClipboard',ai:'scanAI'};
|
|
function icapRequired(policy,channel){if(!Object.hasOwn(CHANNELS,channel))throw Error('Unsupported enterprise inspection channel');const settings=policy.enterprise?.icap;return !!settings?.enabled&&settings[CHANNELS[channel]]!==false;}
|
|
function deploymentTLS(){
|
|
const options={};for(const [key,name] of [['ca','SAFETYNET_ICAP_CA_FILE'],['cert','SAFETYNET_ICAP_CERT_FILE'],['key','SAFETYNET_ICAP_KEY_FILE']]){if(process.env[name]){const stat=fs.statSync(process.env[name]);if(!stat.isFile()||stat.size>131072)throw Error('Enterprise scanner certificate configuration unavailable');options[key]=fs.readFileSync(process.env[name]);}}
|
|
if(!!options.cert!==!!options.key)throw Error('Enterprise scanner client identity incomplete');return options;
|
|
}
|
|
async function scanEnterprise(bytes,policy,channel,scanner){
|
|
const digest=createHash('sha256').update(bytes).digest('hex');
|
|
const base={engine:'icap',sha256:digest,bytes:bytes.length,coverage:{complete:false},decision:'block',ruleId:'icap-unavailable'};
|
|
if(!icapRequired(policy,channel))return {...base,engine:'not-required',decision:'allow',ruleId:null,coverage:{complete:true}};
|
|
const snapshot=Buffer.from(bytes);
|
|
try{
|
|
const result=await (scanner||require('./icap-client.cjs').scanIcap)(snapshot,policy.enterprise.icap,deploymentTLS());
|
|
if(result.decision==='allow'&&result.coverage?.complete===true&&result.sha256===digest&&result.bytes===snapshot.length&&createHash('sha256').update(snapshot).digest('hex')===digest)return {...base,...result};
|
|
return {...base,ruleId:typeof result.ruleId==='string'&&/^icap-[a-z0-9-]{1,80}$/.test(result.ruleId)?result.ruleId:'icap-inspection-incomplete'};
|
|
}catch{return base;}
|
|
finally{snapshot.fill(0);}
|
|
}
|
|
async function scanDownloadEnterprise(bytes,policy,localInspector,scanner){
|
|
const digest=createHash('sha256').update(bytes).digest('hex');
|
|
const blocked=ruleId=>({decision:'block',ruleId,engine:'enterprise',sha256:digest,bytes:bytes.length,coverage:{complete:false}});
|
|
const fileVerdict=inspectFileTransfer(bytes,policy,'download');if(fileVerdict.decision!=='allow')return blocked(fileVerdict.ruleId);
|
|
const noAv=!policy.security?.yara.enabled&&!icapRequired(policy,'download');
|
|
if(noAv&&!policy.fileTransfers?.download?.allowWithoutMalwareScanner)return blocked('malware-scanner-required');
|
|
// Antivirus clean does not classify company secrets. Supported documents always
|
|
// require the contained DLP parser; explicit no-antivirus mode still requires DLP.
|
|
if(noAv||policy.dlp?.semantic?.enabled||['pdf','zip','png','jpeg','gif','webp','text'].includes(detectType(bytes))){
|
|
if(!localInspector?.inspect)return blocked('download-dlp-unavailable');
|
|
let dlp;try{dlp=await localInspector.inspect(bytes,policy);}catch{return blocked('download-dlp-unavailable');}
|
|
if(dlp.decision!=='allow')return blocked(typeof dlp.ruleId==='string'?dlp.ruleId:'download-dlp-blocked');
|
|
if(dlp.coverage?.complete!==true)return blocked('download-dlp-incomplete');
|
|
}
|
|
if(noAv)return {decision:'allow',ruleId:null,engine:'explicit-no-antivirus',sha256:digest,bytes:bytes.length,coverage:{complete:true}};
|
|
if(policy.security?.yara.enabled){
|
|
if(!localInspector)return blocked('yara-unavailable');
|
|
let local;try{local=await localInspector.scanDownload(bytes,policy);}catch{return blocked('yara-unavailable');}
|
|
if(local.decision!=='allow')return local;
|
|
if(local.coverage?.complete!==true||local.sha256!==digest||local.bytes!==bytes.length)return blocked('yara-inspection-incomplete');
|
|
if(!icapRequired(policy,'download'))return local;
|
|
}
|
|
return scanEnterprise(bytes,policy,'download',scanner);
|
|
}
|
|
module.exports={icapRequired,scanEnterprise,scanDownloadEnterprise,deploymentTLS};
|