Skip to content
Snippets Groups Projects
Commit 7aeef3e9 authored by nightfox's avatar nightfox
Browse files

Digital Distortion Upload Processor for Synchronet - Performs a virus scan on...

Digital Distortion Upload Processor for Synchronet - Performs a virus scan on uploaded files (first extracting the file, if it's an archive).  Command lines for archive extraction and virus scan are configurable.
parent c3407315
No related branches found
No related tags found
No related merge requests found
; This is the general configuration file for Digital Distortion
; Upload Processor. This contains options for the processor
; itself.
; In the scan command, the following specifiers can be used:
; Specifier Replaced with
; %FILESPEC% The name of the file/directory to scan
;
; The virus scanner should be able to take just a directory name (to
; scan that entire directory) so that archive files can be unpacked
; into a directory and scanned.
;
; This scan command is for AVG 9; you may need to change the path for your computer.
scanCmd="C:\Program Files\AVG\AVG9\avgscanx.exe" /SCAN=%FILESPEC%
; The following option sets whether or not to pause for the user to
; enter a key after a file is scanned. Valid values are yes and
; no.
pauseAtEnd=no
; If the following setting is set to yes, then all uploads by
; sysops will be automatically approved. Valid values are yes
; and no.
skipScanIfSysop=no
\ No newline at end of file
/* Name: Digital Distortion Upload Processor
*
* Description: This is a script for Synchronet that scans
* uploaded files with a virus scanner. Compressed archives are
* unpacked so that the files inside can be scanned by the virus
* scanner.
*
* Author: Eric Oulashin (AKA Nightfox)
* BBS: Digital Distortion
* BBS address: digdist.bbsindex.com
*
* Date User Description
* 2009-12-25-
* 2009-12-28 Eric Oulashin Initial development
* 2009-12-29 Eric Oulashin Version 1.00
* Initial public release
*/
/* Command-line arguments:
1 (argv[0]): The name of the file to scan
*/
load("sbbsdefs.js");
// Determine the script's execution directory.
// This code is a trick that was created by Deuce, suggested by Rob
// Swindell as a way to detect which directory the script was executed
// in. I've shortened the code a little.
// Note: gStartupPath will include the trailing slash.
var gStartupPath = '.';
try { throw dig.dist(dist); } catch(e) { gStartupPath = e.fileName; }
gStartupPath = backslash(gStartupPath.replace(/[\/\\][^\/\\]*$/,''));
load(gStartupPath + "DDUP_Cleanup.js");
// Version information
var gDDUPVersion = "1.00";
var gDDUPVerDate = "2009-12-29";
// If the filename was specified on the command line, then use that
// for the filename. Otherwise, read the name of the file to view
// from DDArcViewerFilename.txt in the node directory.
var gFileToScan = "";
if (argv.length > 0)
{
if (typeof(argv[0]) == "string")
{
// Make sure the arguments are correct (in case they have spaces),
// then use the first one.
var fixedArgs = fixArgs(argv);
if ((typeof(fixedArgs[0]) == "string") && (fixedArgs[0].length > 0))
gFileToScan = fixedArgs[0];
else
{
console.print("nyhError: ncBlank filename argument given.\r\np");
exit(-2);
}
}
else
{
console.print("nyhError: ncUnknown command-line argument specified.\r\np");
exit(-1);
}
}
else
{
// Read the filename from DDArcViewerFilename.txt in the node directory.
// This is a workaround for file/directory names with spaces in
// them, which would get separated into separate command-line
// arguments for JavaScript scripts.
var filenameFileFilename = system.node_dir + "DDArcViewerFilename.txt";
var filenameFile = new File(filenameFileFilename);
if (filenameFile.open("r"))
{
if (!filenameFile.eof)
gFileToScan = filenameFile.readln(2048);
filenameFile.close();
}
}
// Make sure the slashes in the filename are correct for the platform.
if (gFileToScan.length > 0)
gFileToScan = fixPathSlashes(gFileToScan);
// A filename must be specified as the first argument, so give an error and return
// if not.
if (gFileToScan.length == 0)
{
console.print("nyhError: ncNo filename specified to process.\r\np");
exit(1);
}
// Create the global configuration objects.
var gGenCfg = new Object();
gGenCfg.scanCmd = "";
gGenCfg.skipScanIfSysop = false;
gGenCfg.pauseAtEnd = false;
var gFileTypeCfg = new Object();
// Read the configuration files to populate the global configuration object.
var configFileRead = ReadConfigFile(gStartupPath);
// If the configuration files weren't read, then output an error and exit.
if (!configFileRead)
{
console.print("nyhError: ncUpload processor is unable to read its\r\n");
console.print("configuration files.\r\np");
exit(2);
}
// Exit if there is no scan command.
if (gGenCfg.scanCmd.length == 0)
{
console.print("nyhWarning: ncNo scan command configured for the upload processor.\r\n");
exit(0);
}
// Global variables
// Strings for the OK and failure symbols
var gOKStr = "nkh[ngûkh]n";
var gOKStrWithNewline = gOKStr + "\r\n";
var gFailStr = "nkh[rXk]n";
var gFailStrWithNewline = gFailStr + "\r\n";
// Stuff for the printf formatting string for the status messages
var gStatusTextLen = 79 - console.strlen(gOKStr); // gOKStr and gFailStr should have the same length
var gStatusPrintfStr = "n%s%-" + gStatusTextLen + "sn"; // For a color and the status text
// Now, scan the file and return the appropriate return code.
exit(main());
// End of script execution.
// This is the "main" function that contains the main code
// for the script.
//
// Return value: An integer to return upon script exit.
function main()
{
// Output the program name & version information
console.print("n\r\nchDncigital hDncistortion hUncpload hPncrocessor whvng" +
gDDUPVersion);
// Originally I had this script output the version date, but now I'm not sure
// if I want to do that..
//console.print(" wh(b" + gDDUPVerDate + "w)");
console.print("n");
console.crlf();
// Process the file
var exitCode = processFile(gFileToScan);
// Depending on the exit code, display a success or failure message.
console.crlf();
if (exitCode == 0)
console.print(gOKStr + " nbhScan successful - The file passed.\r\n");
else
console.print(gFailStr + " nyhScan failed!\r\n");
// If the option to pause at the end is enabled, then prompt the user for
// a keypress.
if (gGenCfg.pauseAtEnd)
{
console.print("nwhPress any key to continue:n");
console.getkey(K_NOECHO);
}
return exitCode;
}
//////////////////////////////////////////////////////////////////////////////////
// Object stuff
// Constructor for the ScannableFile object, which contains information
// about a viewable file.
//
// Parameters:
// pExtension: The filename extension
// pViewCmd: The OS command to view it
//
// The ScannableFile object contains the following properties:
// extension: The filename extension
// pExtractCmd: The OS command to extract it (if applicable)
// pScanOption: A string containing a scan option. The following are valid:
// "scan": Always scan the file using the scan commdn
// "always pass": Don't scan the file, and assume it's good
// "always fail": Don't scan the file, and assume it's bad
function ScannableFile(pExtension, pExtractCmd, pScanOption)
{
this.extension = ""; // The archive filename extension
this.extractCmd = ""; // The command to extract the archive (if applicable)
this.scanOption = "scan"; // The scan option ("scan", "always pass", "always fail")
// If the parameters are valid, then use them to set the object properties.
if ((pExtension != null) && (pExtension != undefined) && (typeof(pExtension) == "string"))
this.extension = pExtension;
if ((pExtractCmd != null) && (pExtractCmd != undefined) && (typeof(pExtractCmd) == "string"))
this.extractCmd = pExtractCmd;
if ((pScanOption != null) && (pScanOption != undefined) && (typeof(pScanOption) == "string"))
this.scanOption = pScanOption;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Functions
// This function fixes an array of command-line arguments so that
// arguments with spaces in them are a single argument. This function
// was written by Tracker1 of The Roughnecks BBS - He posted the code
// in the DOVE-Net Synchronet Discussion sub-board on December 20, 2009.
function fixArgs(input)
{
var patt1 = /\"[^\"]*\"|\S+/g;
var patt2 = /^\"?([^\"]*)\"?$/;
return input.join(' ').match(patt1).map(function(item)
{
return item.replace(patt2, "$1")
});
}
// Scans a file.
//
// Parameters:
// pFilename: The name of the file to scan
//
// Return value: A return code from scanning the file. 0 means success;
// non-zero means failure.
function processFile(pFilename)
{
// Display the program header stuff - The name of the file being scanned
// and the status header line
var justFilename = getFilenameFromPath(pFilename);
console.print("nwhScanning b" + justFilename.substr(0, 70));
console.print("n\r\nb7 File Scan Status n\r\n");
// If the skipScanIfSysop option is enabled and the user is a sysop,
// then assume the file is good.
if (gGenCfg.skipScanIfSysop && user.compare_ars("SYSOP"))
{
printf(gStatusPrintfStr, "gh", "Auto-approving the file (you're a sysop)");
console.print(gOKStrWithNewline);
return 0;
}
var retval = 0;
// Look for the file extension in gFileTypeCfg to get the file scan settings.
// If the file extension is not there, then go ahead and scan it (to be on the
// safe side).
var filenameExtension = getFilenameExtension(pFilename);
if (typeof(gFileTypeCfg[filenameExtension]) != "undefined")
{
if (gFileTypeCfg[filenameExtension].scanOption == "scan")
{
// - If the file has an extract command, then:
// Extract the file to a temporary directory in the node dir
// For each file in the directory:
// If it's a subdir
// Recurse into it
// else
// Scan it for viruses
// If non-zero retval
// Return with error code
var filespec = pFilename;
if (gFileTypeCfg[filenameExtension].extractCmd.length > 0)
{
// Create the base work directory for this script in the node dir.
// And just in case that dir already exists, remove it before
// creating it.
var baseWorkDir = system.node_dir + "DDUploadProcessor_Temp";
deltree(baseWorkDir + "/");
if (!mkdir(baseWorkDir))
{
console.print("nyhWarning: nwh Unable to create the work dir.n\r\n");
retval = -1;
}
// If all is okay, then create the directory in the temporary work dir.
var workDir = baseWorkDir + "/" + justFilename + "_temp";
if (retval == 0)
{
deltree(workDir + "/");
if (!mkdir(workDir))
{
console.print("nyhWarning: nwh Unable to create a dir in the temporary work dir.n\r\n");
retval = -1;
}
}
// If all is okay, we can now process the file.
if (retval == 0)
{
// Extract the file to the work directory
printf(gStatusPrintfStr, "mh", "Extracting the file...");
var errorStr = extractFileToDir(pFilename, workDir);
if (errorStr.length == 0)
{
console.print(gOKStrWithNewline);
// Scan the files in the work directory.
printf(gStatusPrintfStr, "r", "Scanning files inside the archive for viruses...");
var retObj = scanFilesInDir(workDir);
retval = retObj.returnCode;
if (retObj.returnCode == 0)
console.print(gOKStrWithNewline);
else
{
console.print(gFailStrWithNewline);
console.print("nyhVirus scan failed. Scan output:n\r\n");
for (var index = 0; index < retObj.cmdOutput.length; ++index)
{
console.print(retObj.cmdOutput[index]);
console.crlf();
}
}
}
else
{
console.print(gFailStrWithNewline);
// Scan the files in the work directory.
console.print("nyhWarning: nwh Unable to extract to work dir.n\r\n");
retval = -2;
}
}
// Remove the work directory.
deltree(baseWorkDir + "/");
}
else
{
// The file has no extract command, so just scan it.
printf(gStatusPrintfStr, "bh", "Scanning...");
var scanCmd = gGenCfg.scanCmd.replace("%FILESPEC%", "\"" + fixPathSlashes(pFilename) + "\"");
// Run the scan command and capture its output, in case the scan fails.
var retObj = runExternalCmdWithOutput(scanCmd);
retval = retObj.returnCode;
if (retObj.returnCode == 0)
console.print(gOKStrWithNewline);
else
{
console.print(gFailStrWithNewline);
console.print("nyhVirus scan failed. Scan output:n\r\n");
for (var index = 0; index < retObj.cmdOutput.length; ++index)
{
console.print(retObj.cmdOutput[index]);
console.crlf();
}
}
}
}
else if (gFileTypeCfg[filenameExtension].scanOption == "always fail")
exitCode = 10;
}
else
{
// There's nothing configured for the file's extension, so just scan it.
printf(gStatusPrintfStr, "r", "Scanning...");
var scanCmd = gGenCfg.scanCmd.replace("%FILESPEC%", "\"" + fixPathSlashes(pFilename) + "\"");
var retObj = runExternalCmdWithOutput(scanCmd);
retval = retObj.returnCode;
if (retObj.returnCode == 0)
console.print(gOKStrWithNewline);
else
{
console.print(gFailStrWithNewline);
console.print("nyhVirus scan failed. Scan output:n\r\n");
for (var index = 0; index < retObj.cmdOutput.length; ++index)
{
console.print(retObj.cmdOutput[index]);
console.crlf();
}
}
}
return retval;
}
// Recursively scans the files in a directory using the scan command in
// gGencfg.
//
// Parameters:
// pDir: The directory to scan
//
// Return value: 0 on success, or non-zero on error.
// Return value: An object containing the following properties:
// returnCode: The return code of the last scan command called in the
// OS (0 is good, non-zero is failure).
// cmdOutput: An array of strings containing the output from the last
// file scan.
function scanFilesInDir(pDir)
{
// If pDir is unspecified, then just return.
if (typeof(pDir) != "string")
{
var retObj = new Object();
retObj.cmdOutput = new Array();
retObj.returnCode = -1;
return retObj;
}
if (pDir.length == 0)
{
var retObj = new Object();
retObj.cmdOutput = new Array();
retObj.returnCode = -2;
return retObj;
}
// Also, just return if gGenCfg.scanCmd is blank.
if (gGenCfg.scanCmd.length == 0)
{
var retObj = new Object();
retObj.cmdOutput = new Array();
retObj.returnCode = -3;
return retObj;
}
// If the filename has a trailing slash, remove it.
if ((/\/$/.test(pDir)) || (/\\$/.test(pDir)))
pDir = pDir.substr(0, pDir.length-1);
var retObj = null; // Will be used to capture the return from the scan commands
// If the virus scan command contains %FILESPEC%, then
// replace %FILESPEC% with pDir and run the scan command.
if (gGenCfg.scanCmd.indexOf("%FILESPEC%") > -1)
{
var scanCmd = gGenCfg.scanCmd.replace("%FILESPEC%", "\"" + fixPathSlashes(pDir) + "\"");
retObj = runExternalCmdWithOutput(scanCmd);
// This is old code, for scanning each file individually (slow):
/*
// Get a list of the files, and scan them.
var files = directory(pDir + "/*");
if (files.length > 0)
{
var scanCmd = null; // Will be used for the scan commands (string)
var counter = 0; // Loop variable
for (var i in files)
{
// If the file is a directory, then recurse into it. Otherwise,
// scan the file using the configured scan command.
if (file_isdir(files[i]))
retObj = scanFilesInDir(files[i]);
else
{
scanCmd = gGenCfg.scanCmd.replace("%FILESPEC%", "\"" + fixPathSlashes(files[i]) + "\"");
// Run the scan command and capture its output, in case the scan fails.
retObj = runExternalCmdWithOutput(scanCmd);
}
// If there's a problem, then stop going through the list of files.
if (retObj.returnCode != 0)
break;
}
}
else
{
// There are no files. So create retObj with default settings
// for a good result.
retObj = new Object();
retObj.returnCode = 0;
retObj.cmdOutput = new Array();
}
*/
}
else
{
// gGenCfg.scanCmd doesn't contain %FILESPEC%, so set up
// retObj with a non-zero return code (for failure)
retObj = new Object();
retObj.returnCode = -4;
retObj.cmdOutput = new Array();
retObj.cmdOutput.push("The virus scanner is not set up correctly.");
}
return retObj;
}
// Reads the configuration file and returns an object containing the
// configuration settings.
//
// Parameters:
// pCfgFilePath: The path from which to load the configuration file.
//
// Return value: Boolean - Whether or not the configuration was read.
function ReadConfigFile(pCfgFilePath)
{
// Read the file type settings.
var fileTypeSettingsRead = false;
var fileTypeCfgFile = new File(pCfgFilePath + "DDUPFileTypes.cfg");
if (fileTypeCfgFile.open("r"))
{
if (fileTypeCfgFile.length > 0)
{
fileTypeSettingsRead = true;
// Read each line from the config file and set the
// various options.
var pos = 0; // Index of = in the file lines
var fileLine = "";
var filenameExt = ""; // Archive filename extension
var option = ""; // Configuration option
var optionValue = ""; // Configuration option value
var optionValueUpper; // Upper-cased configuration option value
var scannableFile = null; // Will be used to create & store scannable file options
while (!fileTypeCfgFile.eof)
{
// Read the line from the config file, look for a =, and
// if found, read the option & value and set them
// in cfgObj.
fileLine = fileTypeCfgFile.readln(1024);
// fileLine should be a string, but I've seen some cases
// where it isn't, so check its type.
if (typeof(fileLine) != "string")
continue;
// If the line is blank or starts with with a semicolon
// (the comment character), then skip it.
if ((fileLine.length == 0) || (fileLine.substr(0, 1) == ";"))
continue;
// Look for a file extension in square brackets ([ and ]).
// If found, then set filenameExt and continue onto the next line.
// Note: This regular expression allows whitespace around the [...].
if (/^\s*\[.*\]\s*$/.test(fileLine))
{
var startIndex = fileLine.indexOf("[") + 1;
var endIndex = fileLine.lastIndexOf("]");
var ext = fileLine.substr(startIndex, endIndex-startIndex).toUpperCase();
// If the filename extension is different than the last one
// we've seen, then:
// 1. If scannableFile is not null, then add it to gScannableFileTypes.
// 2. Create a new one (referenced as scannableFile).
if (ext != filenameExt)
{
if ((scannableFile != null) && (scannableFile != undefined) &&
(filenameExt.length > 0))
{
gFileTypeCfg[filenameExt] = scannableFile;
}
filenameExt = ext;
scannableFile = new ScannableFile(ext, "", "scan");
}
continue;
}
// If filenameExt is blank, then continue onto the next line.
if (filenameExt.length == 0)
continue;
// If we're here, then filenameExt is set, and this is a valid
// line to process.
// Look for an = in the line, and if found, split into
// option & value.
pos = fileLine.indexOf("=");
if (pos > -1)
{
// Extract the option & value, trimming leading & trailing spaces.
option = trimSpaces(fileLine.substr(0, pos), true, false, true).toUpperCase();
optionValue = trimSpaces(fileLine.substr(pos+1), true, false, true);
if (option == "EXTRACT")
scannableFile.extractCmd = optionValue;
else if (option == "SCANOPTION")
scannableFile.scanOption = optionValue;
}
}
}
fileTypeCfgFile.close();
}
// Read the general program configuration
var genSettingsRead = false;
var genCfgFile = new File(pCfgFilePath + "DDUP.cfg");
if (genCfgFile.open("r"))
{
if (genCfgFile.length > 0)
{
genSettingsRead = true;
var fileLine = null; // A line read from the file
var equalsPos = 0; // Position of a = in the line
var commentPos = 0; // Position of the start of a comment
var setting = null; // A setting name (string)
var settingUpper = null; // Upper-case setting name
var value = null; // A value for a setting (string)
while (!genCfgFile.eof)
{
// Read the next line from the config file.
fileLine = genCfgFile.readln(1024);
// fileLine should be a string, but I've seen some cases
// where it isn't, so check its type.
if (typeof(fileLine) != "string")
continue;
// If the line starts with with a semicolon (the comment
// character) or is blank, then skip it.
if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0))
continue;
// If the line has a semicolon anywhere in it, then remove
// everything from the semicolon onward.
commentPos = fileLine.indexOf(";");
if (commentPos > -1)
fileLine = fileLine.substr(0, commentPos);
// Look for an equals sign, and if found, separate the line
// into the setting name (before the =) and the value (after the
// equals sign).
equalsPos = fileLine.indexOf("=");
if (equalsPos > 0)
{
// Read the setting & value, and trim leading & trailing spaces.
setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true);
settingUpper = setting.toUpperCase();
value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true);
// Skip this one if the value is blank.
if (value.length == 0)
continue;
// Set the appropriate value in the settings object.
if (settingUpper == "SCANCMD")
gGenCfg.scanCmd = value;
else if (settingUpper == "SKIPSCANIFSYSOP")
gGenCfg.skipScanIfSysop = (value.toUpperCase() == "YES");
else if (settingUpper == "PAUSEATEND")
gGenCfg.pauseAtEnd = (value.toUpperCase() == "YES");
}
}
genCfgFile.close();
}
}
return (fileTypeSettingsRead && genSettingsRead);
}
// Removes multiple, leading, and/or trailing spaces
// The search & replace regular expressions used in this
// function came from the following URL:
// http://qodo.co.uk/blog/javascript-trim-leading-and-trailing-spaces
//
// Parameters:
// pString: The string to trim
// pLeading: Whether or not to trim leading spaces (optional, defaults to true)
// pMultiple: Whether or not to trim multiple spaces (optional, defaults to true)
// pTrailing: Whether or not to trim trailing spaces (optional, defaults to true)
function trimSpaces(pString, pLeading, pMultiple, pTrailing)
{
var leading = true;
var multiple = true;
var trailing = true;
if (typeof(pLeading) != "undefined")
leading = pLeading;
if (typeof(pMultiple) != "undefined")
multiple = pMultiple;
if (typeof(pTrailing) != "undefined")
trailing = pTrailing;
// To remove both leading & trailing spaces:
//pString = pString.replace(/(^\s*)|(\s*$)/gi,"");
if (leading)
pString = pString.replace(/(^\s*)/gi,"");
if (multiple)
pString = pString.replace(/[ ]{2,}/gi," ");
if (trailing)
pString = pString.replace(/(\s*$)/gi,"");
return pString;
}
// Returns a filename's extension. Always returns a string.
//
// Parameters:
// pFilename: The name of a file
//
// Return value: The filename's extension, or blank if there is none.
function getFilenameExtension(pFilename)
{
const filenameUpper = pFilename.toUpperCase();
var filenameExt = "";
// Special case for .tar.gz - Report tar.gz as an extension
// rather than just gz
if (/.TAR.GZ$/.test(filenameUpper))
filenameExt = "TAR.GZ";
else
{
// Look for the last period in filenameUpper
var dotIndex = filenameUpper.lastIndexOf(".");
if (dotIndex > -1)
filenameExt = filenameUpper.substr(dotIndex+1);
}
return filenameExt;
}
// This function returns just the filename from the end of a full path, regardless
// of whether it has a trailing slash.
//
// Parameters:
// pFilename: The full path & filename
//
// Return value: Just the filename from the end of the path
function getFilenameFromPath(pFilename)
{
var filename = pFilename;
if (filename.length > 0)
{
// If the filename has a trailing slash, remove it. Then,
// use file_getname() to get the filename from the end.
if ((/\/$/.test(filename)) || (/\\$/.test(filename)))
filename = filename.substr(0, filename.length-1);
filename = file_getname(filename);
}
return filename;
}
// Given a full path & filename, this function returns just the path portion,
// with a trailing slash.
//
// Parameters:
// pFilename: A filename with the full path
//
// Return value: Just the path portion of the filename.
function getPathFromFilename(pFilename)
{
// Make sure pFilename is valid
if ((pFilename == null) || (pFilename == undefined))
return "";
if (typeof(pFilename) != "string")
return "";
if (pFilename.length == 0)
return "";
// Determine which slash character to use for paths, depending
// on the OS.
if (getPathFromFilename.inWin == undefined)
getPathFromFilename.inWin = /^WIN/.test(system.platform.toUpperCase());
var pathSlash = (getPathFromFilename.inWin ? "\\" : "/");
// Make sure the filename has the correct slashes for
// the platform.
var filename = fixPathSlashes(pFilename);
// If pFilename is actually a directory, then just return it.
if (file_isdir(filename))
{
// Make sure it has a trailing slash that's appropriate
// for the OS.
var lastChar = filename.charAt(filename.length-1);
if ((lastChar != "/") || (lastChar == "\\"))
filename += pathSlash;
return filename;
}
// Find the index of the last slash and use that to extract the path.
var path = "";
var lastSlashIndex = filename.lastIndexOf(pathSlash);
if (lastSlashIndex > 0)
path = filename.substr(0, lastSlashIndex);
// If we extracted the path, make sure it ends with a slash.
if (path.length > 0)
{
var lastChar = path.charAt(path.length-1);
if (lastChar != pathSlash)
path += pathSlash;
}
return path;
}
// Fixes all slashes in a given path to be the appropriate slash
// character for the OS. Returns a new string with the fixed version.
//
// Parameters:
// pPath: A path to fix
//
// Return value: The fixed version of pPath
function fixPathSlashes(pPath)
{
// Make sure pPath is valid.
if ((pPath == null) || (pPath == undefined))
return "";
if (typeof(pPath) != "string")
return "";
if (pPath.length == 0)
return "";
// Create a variable to store whether or not we're in Windows,
// but only once (for speed).
if (fixPathSlashes.inWin == undefined)
fixPathSlashes.inWin = /^WIN/.test(system.platform.toUpperCase());
// Fix the slashes and return the fixed version.
//return(fixPathSlashes.inWin ? pPath.replace("/", "\\") : pPath.replace("\\", "/"));
var path = pPath;
if (fixPathSlashes.inWin) // Windows
{
while (path.indexOf("/") > -1)
path = path.replace("/", "\\");
}
else // *nix
{
while (path.indexOf("\\") > -1)
path = path.replace("\\", "/");
}
return path;
}
// This function extracts a file to a directory.
//
// Parameters:
// pFilename: The name of the file to extract
// pWorkDir: The directory to extract the file into. This directory must
// exist before calling this function.
//
// Return value: A blank string on success, or an error message on failure.
function extractFileToDir(pFilename, pWorkDir)
{
// If pFilename doesn't exist, then return with an error.
if (typeof(pFilename) != "string")
return ("Invalid filename specified.");
if (pFilename.length == 0)
return ("No filename specified.");
if (!file_exists(pFilename))
return ("The specified file does not exist.");
// If pWorkDir is blank, then return with an error.
if (typeof(pWorkDir) != "string")
return ("Unknown argument specified for the work directory.");
if (pWorkDir.length == 0)
return ("No work directory specified.");
// If pWorkDir ends with a slash, remove it.
if ((/\/$/.test(pWorkDir)) || (/\\$/.test(pWorkDir)))
pWorkDir = pWorkDir.substr(0, pWorkDir.length-1);
// If the work directory doesn't exist, then return with
// an error.
// Note: file_exists() doesn't seem to work properly with directories.
//if (!file_exists(pWorkDir))
// return ("The work directory doesn't exist.");
var filenameExt = getFilenameExtension(pFilename);
// Return with errors if there are problems.
if (filenameExt.length == 0)
return ("Can't extract (no file extension).");
if (typeof(gFileTypeCfg[filenameExt]) == "undefined")
return ("Can't extract " + getFilenameFromPath(pFilename) + " (I don't know how).");
if (gFileTypeCfg[filenameExt].extractCmd == "")
return ("Can't extract " + getFilenameFromPath(pFilename) + " (I don't know how).");
var retval = "";
// Extract the file to the work directory.
var extractCmd = gFileTypeCfg[filenameExt].extractCmd.replace("%FILENAME%", "\"" + fixPathSlashes(pFilename) + "\"");
extractCmd = extractCmd.replace("%FILESPEC% ", "");
extractCmd = extractCmd.replace("%TO_DIR%", "\"" + fixPathSlashes(pWorkDir) + "\"");
var retCode = system.exec(extractCmd);
if (retCode != 0)
return ("Extract failed with exit code " + retCode);
// For each file in the work directory:
// If the file has an extract command
// Extract it to a subdir in the temp dir
// Delete the archive
var files = directory(pWorkDir + "/*");
for (var i in files)
{
// If the file has an extract command, then extract it to a
// temp directory in the work directory.
filenameExt = getFilenameExtension(files[i]);
if ((typeof(gFileTypeCfg[filenameExt]) != "undefined") &&
((gFileTypeCfg[filenameExt].extractCmd != "")))
{
// Create the temp directory and extract the file there.
var workDir = pWorkDir + "/" + getFilenameFromPath(files[i] + "_temp");
if (mkdir(workDir))
retval = extractFileToDir(files[i], workDir);
else
retval = "Unable to create a temporary directory.";
// If there was no problem, then delete the archive file. Otherwise,
// stop going through the list of files.
if (retval.length == 0)
file_remove(files[i]);
else
break;
}
}
return retval;
}
// This function executes an OS command and returns its output as an
// array of strings. The reason this function was written is that
// system.popen() is only functional in UNIX.
//
// Parameters:
// pCommand: The command to execute
//
// Return value: An object containing the following properties:
// returnCode: The return code of the OS command
// cmdOutput: An array of strings containing the program's output.
function execCmdWithOutput(pCommand)
{
var retObj = new Object();
retObj.returnCode = 0;
retObj.cmdOutput = new Array();
if ((pCommand == undefined) || (pCommand == null) || (typeof(pCommand) != "string"))
return retObj;
// Execute the command and redirect the output to a file in the
// node's directory. system.exec() returns the return code that the
// command returns; generally, 0 means success and non-zero means
// failure (or an error of some sort).
const tempFilename = system.node_dir + "DDUPCommandOutput_temp.txt";
retObj.returnCode = system.exec(pCommand + " >" + tempFilename + " 2>&1");
// Read the temporary file and populate retObj.cmdOutput with its
// contents.
var tempFile = new File(tempFilename);
if (tempFile.open("r"))
{
if (tempFile.length > 0)
{
var fileLine = null;
while (!tempFile.eof)
{
fileLine = tempFile.readln(2048);
// fileLine should be a string, but I've seen some cases
// where it isn't, so check its type.
if (typeof(fileLine) != "string")
continue;
retObj.cmdOutput.push(fileLine);
}
}
tempFile.close();
}
// Remove the temporary file, if it exists.
if (file_exists(tempFilename))
file_remove(tempFilename);
return retObj;
}
// Runs an external command. This function was written because
// I want to be able to handle executable files with spaces in
// their name/path (system.exec() doesn't handle said spaces).
//
// Parameters:
// pCommand: The command to execute
//
// Return value: An object containing the following properties:
// returnCode: The return code of the OS command
// cmdOutput: An array of strings containing the program's output.
function runExternalCmdWithOutput(pCommand)
{
// Determine whether or not we're in Windows.
if (runExternalCmdWithOutput.inWin == undefined)
runExternalCmdWithOutput.inWin = /^WIN/.test(system.platform.toUpperCase());
var retObj = null; // The return object
var wroteScriptFile = false; // Whether or not we were able to write the script file
// In the node directory, write a batch file (if in Windows) or a *nix shell
// script (if not in Windows) containing the command to run.
var scriptFilename = "";
if (runExternalCmdWithOutput.inWin)
{
// Write a Windows batch file to run the command
scriptFilename = fixPathSlashes(system.node_dir + "DDUP_ScanCmd.bat");
//console.print(":" + scriptFilename + ":\r\n\1p"); // Temporary (for debugging)
var scriptFile = new File(scriptFilename);
if (scriptFile.open("w"))
{
scriptFile.writeln("@echo off");
scriptFile.writeln(pCommand);
scriptFile.close();
wroteScriptFile = true;
retObj = execCmdWithOutput(scriptFilename);
}
}
else
{
// Write a *nix shell script to run the command
scriptFilename = system.node_dir + "DDUP_ScanCmd.sh";
var scriptFile = new File(scriptFilename);
if (scriptFile.open("w"))
{
scriptFile.writeln("#!/bin/bash"); // Hopefully /bin/bash is valid on the system!
scriptFile.writeln(pCommand);
scriptFile.close();
wroteScriptFile = true;
system.exec("chmod ugo+x " + scriptFilename);
retObj = execCmdWithOutput("bash " + scriptFilename);
}
}
// Remove the script file, if it exists
if (file_exists(scriptFilename))
file_remove(scriptFilename);
// If we were unable to write the script file, then create retObj with
// a returnCode indicating failure.
if (!wroteScriptFile)
{
// Could not open the script file for writing
retObj = new Object();
retObj.cmdOutput = new Array();
retObj.returnCode = -1;
}
return retObj;
}
\ No newline at end of file
; This is the file type configuration for Digital Distortion Upload Processor.
; Compressed archive file extensions
[ZIP]
scanOption=scan
; PKZip for Win32
;EXTRACT=\BBS\COMPRESS\pkzip25.exe -extract -NoZipExtension -Directories %FILENAME% %FILESPEC% %TO_DIR%
; Info-ZIP for Win32 console (comes with Synchronet)
EXTRACT=\BBS\sbbs\exec\unzip.exe -qq -o %FILENAME% %FILESPEC% -d %TO_DIR%
; Info-ZIP, *nix
;EXTRACT=unzip -qq -o %FILENAME% %FILESPEC% -d %TO_DIR%
; 7-Zip for Win32 console
;EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
[7Z]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
[RAR]
scanOption=scan
; RAR for Win32 console
EXTRACT=\BBS\COMPRESS\Rar.exe x -p- -y %FILENAME% %FILESPEC% %TO_DIR%
; Alexander Roshal's unrar for *nix
;EXTRACT=unrar x %FILENAME% %FILESPEC% %TO_DIR%
[ARJ]
scanOption=scan
; ARJ for Win32 console
EXTRACT=\BBS\COMPRESS\ARJ32.EXE x -y %FILENAME% %FILESPEC% -ht%TO_DIR%
; Open-Source ARJ for *nix
;EXTRACT=arj x %FILENAME% %FILESPEC% -ht%TO_DIR%
[ISO]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
[TAR]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
[GZ]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
[TGZ]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
[TAR.GZ]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; tar for *nix
;EXTRACT=cd %TO_DIR% && tar zxvf %FILENAME%
; Microsoft Installer file
[MSI]
scanOption=scan
; 7-Zip for Win32 console
EXTRACT=\BBS\COMPRESS\7za.exe x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; 7-Zip for *nix
;EXTRACT=7za x -y -pxyz %FILENAME% %FILESPEC% -o%TO_DIR%
; Text file extensions
[TXT]
scanOption=always pass
[DIZ]
scanOption=always pass
[DOC]
scanOption=scan
[ANS]
scanOption=always pass
[ASC]
scanOption=always pass
[ASCII]
scanOption=always pass
[RIP]
scanOption=always pass
[NFO]
scanOption=always pass
; Chinese text file
[ZW]
scanOption=always pass
[NEW]
scanOption=always pass
[BBS]
scanOption=always pass
[ICE]
scanOption=always pass
[LOG]
scanOption=always pass
; Guitar tab file
[TAB]
scanOption=always pass
; Guitar tab file
[CRD]
scanOption=always pass
; Guitar tab file
[CHORD]
scanOption=always pass
; Readme file (i.e., READ.ME)
[ME]
scanOption=always pass
[FAQ]
scanOption=always pass
[NOW]
scanOption=always pass
[HTM]
scanOption=always pass
[HTML]
scanOption=always pass
[REG]
scanOption=scan
; A readme file, as in README.1ST
[1ST]
scanOption=always pass
[CFG]
scanOption=always pass
[INI]
scanOption=always pass
; Batch file
[BAT]
scanOption=always pass
; Command list file (similar to a DOS batch file)
[CMD]
scanOption=always pass
; REXX script (a programming language developed by IBM)
[REXX]
scanOption=always pass
; *nix shell script
[SH]
scanOption=always pass
; Outlook Express email message
[EMAIL]
scanOption=scan
; Mail message
[EMLX]
scanOption=scan
; EditPad Pro
[EPP]
scanOption=always pass
; Error log
[ERR]
scanOption=always pass
; Outlook Express mailbox index file
[IDX]
scanOption=scan
; Data list
[LST]
scanOption=always pass
\ No newline at end of file
/* This is a cleanup script for Digital Distortion Upload Processor.
* This script cleans up temporary files & directories from the
* node directory used by Digital Distortion Upload Processor.
*
* Author: Eric Oulashin (AKA Nightfox)
* BBS: Digital Distortion
* BBS address: digdist.bbsindex.com
*
* Date User Description
* 2009-12-26 Eric Oulashin Created
* 2009-12-28 Eric Oulashin Added removal of DDUPCommandOutput_temp.txt
* and DDUP_ScanCmd.*
*/
load("sbbsdefs.js");
// Remove the temporary work directory used by Digital Distortion
// Upload Processor.
deltree(system.node_dir + "DDUploadProcessor_Temp");
// Remove DDUPCommandOutput_temp.txt from the node directory
file_remove(system.node_dir + "DDUPCommandOutput_temp.txt");
// Remove the command script from the node directory
file_remove(system.node_dir + "DDUP_ScanCmd.*");
/////////////////////////////////////////////////////////////////////////////////
// Functions
// This function recursively removes a directory and all of its contents. Returns
// whether or not the directory was removed.
//
// Parameters:
// pDir: The directory to remove (with trailing slash).
//
// Return value: Boolean - Whether or not the directory was removed.
function deltree(pDir)
{
if ((pDir == null) || (pDir == undefined))
return false;
if (typeof(pDir) != "string")
return false;
if (pDir.length == 0)
return false;
// Make sure pDir actually specifies a directory.
if (!file_isdir(pDir))
return false;
// Don't wipe out a root directory.
if ((pDir == "/") || (pDir == "\\") || (/:\\$/.test(pDir)) || (/:\/$/.test(pDir)) || (/:$/.test(pDir)))
return false;
// If we're on Windows, then use the "RD /S /Q" command to delete
// the directory. Otherwise, assume *nix and use "rm -rf" to
// delete the directory.
if (deltree.inWindows == undefined)
deltree.inWindows = (/^WIN/.test(system.platform.toUpperCase()));
if (deltree.inWindows)
system.exec("RD " + withoutTrailingSlash(pDir) + " /s /q");
else
system.exec("rm -rf " + withoutTrailingSlash(pDir));
// The directory should be gone, so we should return true. I'd like to verify that the
// directory really is gone, but file_exists() seems to return false for directories,
// even if the directory does exist. So I test to make sure no files are seen in the dir.
return (directory(pDir + "*").length == 0);
/*
// Recursively deleting each file & dir using JavaScript:
var retval = true;
// Open the directory and delete each entry.
var files = directory(pDir + "*");
for (var i = 0; i < files.length; ++i)
{
// If the entry is a directory, then deltree it (Note: The entry
// should have a trailing slash). Otherwise, delete the file.
// If the directory/file couldn't be removed, then break out
// of the loop.
if (file_isdir(files[i]))
{
retval = deltree(files[i]);
if (!retval)
break;
}
else
{
retval = file_remove(files[i]);
if (!retval)
break;
}
}
// Delete the directory specified by pDir.
if (retval)
retval = rmdir(pDir);
return retval;
*/
}
// Removes a trailing (back)slash from a path.
//
// Parameters:
// pPath: A directory path
//
// Return value: The path without a trailing (back)slash.
function withoutTrailingSlash(pPath)
{
if ((pPath == null) || (pPath == undefined))
return "";
var retval = pPath;
if (retval.length > 0)
{
var lastIndex = retval.length - 1;
var lastChar = retval.charAt(lastIndex);
if ((lastChar == "\\") || (lastChar == "/"))
retval = retval.substr(0, lastIndex);
}
return retval;
}
\ No newline at end of file
nhc Digital Distortion Upload Processor yvw1.00
hy For Synchronet 3.14+
kÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ncThis is an upload processor for Synchronet
that allows for performing a virus scan on
files inside of archives. File extraction
commands and the virus scan command are
configurable.
bhRelease date: 2009-12-29
\ No newline at end of file
Digital Distortion Upload Processor
Version 1.00
Release date: 2009-12-29
by
Eric Oulashin
Sysop of Digital Distortion BBS
BBS internet address: digitaldistortionbbs.com
digdist.bbsindex.com
Email: eric.oulashin@gmail.com
This file describes the Digital Distortion Upload Processor.
Contents
========
1. Disclaimer
2. Introduction
3. Archive File Software
4. Installation and Setup
5. Main configuration file
6. Archive file type configuration file
1. Disclaimer
=============
The only guarantee that I can make about Digital Distortion Upload Processor
is that it will take up space on your computer. I have tested this with
the Windows verison of Synchronet and with the Windows version of AVG Free
(virus scanner) on my BBS, running in Windows 2000; this script has not
been tested with Linux Synchronet platforms. I created this script because
I felt that it would be useful and am providing it to the Synchronet BBS
community in case other Synchronet sysops might find it useful.
2. Introduction
===============
Digital Distortion Upload Processor is a script makes use of a virus scanner
to scan uploaded files, with the added ability to extract compressed files
in order to scan the files inside the compressed file.
File formats can be specified and configured via a configuration file,
including extraction commands for compressed files. In addition, the
virus scan command can be configured in the main configuration file,
which should allow for the use of any virus scanner, as long as it is a
command-line scanner (no GUI) and is able to take a subdirectory as a
command-line parameter.
Compressed (archive) files will be extracted to a temporary directory in the
node directory after they are uploaded. Furthermore, compressed files
within the compressed file will be extracted to subdirectories within that
subdirectory, and any compressed files inside those compressed files will
be extracted, etc.. This way, all files inside of the archive can be
scanned by the virus scanner.
The temporary directory created in the node directory has the following
name:
DDUploadProcessor_Temp
Additionally, the following temporary files are created in the node
directory:
DDUPCommandOutput_temp.txt
DDUP_ScanCmd.bat (for Win32 systems) or DDUP_ScanCmd.sh (for *nix systems)
The temporary files and temporary directory will be removed when the
script finishes; however, in cases where they aren't removed (i.e., if the
user disconnects during the scan), a cleanup script is also included, which
can be executed in your logon and logoff scripts to ensure that the node
directory does not contain the temporary files.
Detection of viruses will reject the uploaded file. Also, failure to
extract an archive (and thus, inability to scan for viruses) will cause the
uploaded file to be rejected.
3. Archive File Software
========================
Digital Distortion Upload Processor comes with configuration settings to
handle extraction of ZIP, 7Z (7-Zip), RAR, ARJ, MSI, TAR, GZ, TGZ, and
TAR.GZ archives.
The file format configuration file included with this script includes
extraction command lines (specified by an EXTRACT setting) for various
archivers for both Windows and Linux. In order for this script to work
properly, you will need to make sure you have the appropriate archiver
software installed on your system, and you will need to edit the
DDUPFileTypes.cfg file (using a text editor) and make sure you have
EXTRACT command lines set properly for your system. For information on
that configuration file, see section 6: Archive file type configuration
file.
The following archive contains Win32 command-line archivers for popular
archive file formats:
http://digdist.bbsindex.com/miscFilesForDL/Win32CmdLineCompressionTools.zip
The archivers included in that archive handle the most popular file formats
(ZIP, 7Z (7-Zip), RAR, ARJ, TAR, GZ, TGZ, and TAR.GZ), and they are set up in
DDUPFileTypes.cfg to extract popular file formats (ZIP, 7Z (7-Zip), RAR, ARJ,
MSI, TAR, GZ, TGZ, and TAR.GZ). Note that you will need to edit that .cfg
file and change the path to the .exe file according to where you copied them
on your system. If your BBS is running in Windows, the included configuration
file should work for you (although it does also have the Linux command lines
as comments). If you copy the archivers to a directory that is not in your
system path, you will need to edit the DDUPFileTypes.cfg file to include the
full paths with the archive executables.
Extractor notes:
DDUPFileTypes.cfg includes a setup for using 7-Zip to extract ISO (CD/DVD
image) files; however, in testing, it seemed that 7-Zip can only extract
or see one file in an ISO image.
DDUPFileTypes.cfg also includes a setup for extracting MSI (Microsoft
Installer) files.
For Linux, the following is a list of Linux archivers that this
script is configured for and how you can acquire them if you don't
have them already:
------------------
ZIP, 7Z, GZ, TGZ, TAR:
- Install p7zip using your distro's package manager, or download it via
the web. A download page is available here:
http://www.7-zip.org/download.html
RAR:
- Install unrar using your distro's package manager, or download it via
the web. Or, download RARLab's version:
http://www.rarlab.com/download.htm
ARJ:
- Source code for open-Source ARJ (and instructions) are available here:
http://linux.softpedia.com/get/System/Archiving/Arj-12097.shtml
This is the download link from that page:
http://linux.softpedia.com/progDownload/Arj-Download-12097.html
Download the source, and follow the page's instructions to build that on
your Linux system. After compiling, the executable file will be located
in linux-gnu/en/rs/arj . Place the executable file (arj) in a directory
in your path (i.e., /usr/local/bin or /usr/bin).
Instructions for building the ARJ source code, from the above web page,
are as follows:
cd gnu;autoconf;./configure;cd ..;make prepare;make
Notes:
1. GNU make must be used (on FreeBSD systems it's called "gmake").
2. You have to run autoconf prior to running configure - as there will be different configure scripts for UNIX-like systems and OS/2 EMX.
3. On OS/2 EMX, autoconf v 2.57 is confirmed to work.
4. You can finalize the build process with "make install" (to perform a local installation) or "make package" (to create a self-extracting distribution kit).
ARJ is a CPU-intensive program. If you wish to configure ARJ for a higher performance on a specific CPU, try the following, assuming that you have a newer version of GCC, e.g. 3.2.1:
./configure CFLAGS="-march=i386 -mcpu=athlon-xp"
where "-mcpu" designates the type of your CPU, run "man gcc" for a list of CPU types.
4. Installation and Setup
=========================
Step 1: Install a virus scanner
-------------------------------
You will need to download and install a virus scanner on your BBS system.
The one that I set up this script for is AVG Free version 9 for Windows,
which is available at the following web page:
http://free.avg.com/us-en/download?prd=afg
Step 2: Copy the script files, configuration files, & archivers to your system
------------------------------------------------------------------------------
Digital Distortion Upload Processor consists of the following files, which
you will need to place in your sbbs/exec directory (or another directory of
your choice):
1. DDUP.js
2. DDUP.cfg
3. DDUP_Cleanup.js
4. DDUPFileTypes.cfg
For sysops running their BBS in Windows, the following archiver programs
in the Win32Archivers directory will need to be placed in a directory
(preferably a directory that's included in the system's path):
1. 7za.exe
2. ARJ32.EXE
3. Rar.exe
4. unzip.exe
For sysops running the Linux version of Synchronet, you will need to acquire
the appropriate archivers as described in the previous section.
Step 3: Edit the configuration files
------------------------------------
You will need to edit DDUPFileTypes.cfg to make sure that the EXTRACT
command lines are correct for your system. If you're running your BBS
in Linux, you will first need to comment the Windows command lines and
uncomment the Linux command lines. See section 6: Archive file type
configuration file.
You will also need to edit DDUP.cfg and change the scanCmd option, which
specifies the command line to use to scan files for viruses. In this
command line, the text string %FILESPEC% will be replaced with the name
of the file or directory to be scanned; thus, the virus scanner you use
should be able to take the name of an individual file or a directory as
a parameter, and it should also be a command-line scanner (capable of
taking command-line parameters).
Special note about the scanner command line
-------------------------------------------
It should be noted that the scanner command line specified in DDUP.cfg
will be written to a temporary batch file (on Win32 systems) or a shell
script (on *nix systems), which is then run in order to scan the file(s).
The reason for this is that if there are any spaces in the file or
directory names used in the scanner command, the command line doesn't seem
to be passed to the operating system correctly by Synchronet's JavaScript
object model.
Step 4: Set up Digital Distortion Upload Processor for Testable Files
in Synchronet's configuration program (SCFG)
----------------------------------------------------------------------
1. Run Synchronet's configuration program (SCFG)
2. From the main menu, choose "File Options".
3. From the menu that appears, choose "Testable Files..."
4. For each file type that you want to be able to test, you will need
an entry in this table. Some archive file types (i.e., ZIP) might
already be in there. In that case, simply scroll down to it and press
Enter to select it. If the desired file type is not in the list, then
press the INS key to insert an entry or scroll down to the first blank
line and press Enter to insert an entry there, then press Enter to
select and edit it.
The Command Line setting for the file type should look similar to
this (assuming the upload processor files were copied to your
sbbs\exec directory):
?DDUP.js %f
If you copied the upload processor files to another directory, you
will need to provide the path to DDUP.js; for example:
?/sbbs/UploadProcessor/DDUP.js %f
As an example, your Testable File Type window should look similar
to the following:
+[¦][?]--------------------------------------------------------+
¦ Testable File Type ¦
¦--------------------------------------------------------------¦
¦ ¦File Extension ZIP ¦
¦ ¦Command Line ?DDUP.js %f ¦
¦ ¦Working String Scanning arrchive file for viruses... ¦
¦ ¦Access Requirements ¦
+--------------------------------------------------------------+
Step 5: Create/update your logout and scripts to handle temporary file cleanup
------------------------------------------------------------------------------
If you have not already done so, you will need to create logout and login
scripts for your BBS; there, you will want to load DDUP_Cleanup.js - That will
help to ensure that temporary files created by the upload processor will be
removed to prevent extra space on your hard drive being wasted.
If you are not already using a logout script, follow these steps:
1. Create a file in your sbbs\exec directory called logout.js (or another name
of your choosing)
2. Add this line to it (assuming that the upload processor scripts are in
sbbs\exec):
load("DDUP_Cleanup.js");
3. Add your logout script to Synchronet's configuration:
A. Run Synchronet's configuration program (SCFG)
B. From the main menu, choose "System".
C. From that menu, choose "Loadable Modules..."
D. Arrow down to highlight "Logout Event", and press Enter. When it
prompts you, type in "logout" (without the quotes) and press Enter.
E. Escape back to the main menu, saving changes when it asks you to do
so. Then, exit out of SCFG.
If you already have a logout script (using JavaScript), you just need to add the
following line to it:
load("DDUP_Cleanup.js");
It is recommended that you do the same thing with your logout script.
5. Main configuration file
==========================
The file DDUP.cfg contains general settings for the upload processor. This
file can be edited with a text editor. The syntax for each setting is as
folows:
setting=value
where "setting" is the setting name, "value" is the corresponding value for
the setting.
Also, comments are allowed in the configuration file. Comments begin with a
semicolon (;).
The following are the settings used in this configuration file:
Setting Description
------- -----------
scanCmd The command line to use for the virus scanner.
In this command line, the text string
%FILESPEC% will be replaced with the
file/directory to be scanned.
pauseAtEnd Specifies whether or not to pause for user
input when the scan is done. Valid values
are yes and no.
skipScanIfSysop Specifies whether or not to skip scanning
for the sysop(s). Valid values are yes
and no.
6. Archive file type configuration file
=======================================
The configuration file DDUPFileTypes.cfg defines options for various file
types, including the extract command (for archive files) and whether or not
you want the upload processor to scan it. File types are specified by their
filename extension in square brackets. Extractable files must have an
EXTRACT option, which specifies the command line for extracting the file.
Another option that can be specified in this file is scanOption, which
specifies whether or not you want the upload processor to scan the file
(or files in the archive) with the virus scanner.
The general format for each file type is as follows:
[EXTENSION]
EXTRACT=command
scanOption=scan (or always pass, or always fail)
By default, the scanOption setting will be "scan", and by default, the extract
command is blank (not set).
The valid values for the scanOption setting are as follows:
scan: Scan the file using the virus scanner
always pass: Always assume the file is good
always fail: Always assume the file is bad
As an example, the following settings can be used for zip files in Windows:
[ZIP]
scanOption=scan
EXTRACT=\BBS\sbbs\exec\unzip.exe -qq -o %FILENAME% %FILESPEC% -d %TO_DIR%
Note that for the extract command, the following pseudonyms are used:
%FILENAME% : The name of the archive file or text file.
%FILESPEC% : This would specify the file(s) to be extracted from the archive.
The script actually will totally remove this from the command; it
is not used. It's currently here for possible future use.
%TO_DIR% : The directory to which the archive file will be extracted.
Using the above example configuration for zip files, if the user (on node 1)
uploads D:\Files\someArchive.zip and your Synchronet installation is located
in D:\sbbs, the temp directory is D:\sbbs\node1\DDUploadProcessor_Temp, and
the extract command will be translated to the following:
unzip.exe -qq -o D:\Files\someArchive.zip -d D:\sbbs\node1\DDUploadProcessor_Temp
\ No newline at end of file
Revision History for Digital Distortion Upload Processor
========================================================
Version Date Description
------- ---- -----------
1.00 2009-12-29 First general public release
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment