2014-10-17 02:21:06 +00:00
/* jslint node: true */
'use strict' ;
2017-01-28 19:33:06 +00:00
// ENiGMA½
2018-06-14 03:02:00 +00:00
const Errors = require ( './enig_error.js' ) . Errors ;
2014-10-17 02:21:06 +00:00
2017-01-28 19:33:06 +00:00
// deps
const paths = require ( 'path' ) ;
const async = require ( 'async' ) ;
const _ = require ( 'lodash' ) ;
const assert = require ( 'assert' ) ;
2015-04-17 04:29:53 +00:00
2017-01-28 19:33:06 +00:00
exports . init = init ;
exports . getDefaultPath = getDefaultPath ;
2015-04-19 08:13:13 +00:00
2018-06-21 01:57:06 +00:00
let currentConfiguration = { } ;
2016-02-03 04:35:59 +00:00
function hasMessageConferenceAndArea ( config ) {
2018-06-22 05:15:04 +00:00
assert ( _ . isObject ( config . messageConferences ) ) ; // we create one ourself!
2016-09-20 03:28:21 +00:00
2018-06-22 05:15:04 +00:00
const nonInternalConfs = Object . keys ( config . messageConferences ) . filter ( confTag => {
return 'system_internal' !== confTag ;
} ) ;
2016-09-20 03:28:21 +00:00
2018-06-22 05:15:04 +00:00
if ( 0 === nonInternalConfs . length ) {
return false ;
}
2016-09-20 03:28:21 +00:00
2018-06-22 05:15:04 +00:00
// :TODO: there is likely a better/cleaner way of doing this
2016-09-20 03:28:21 +00:00
2018-06-22 05:15:04 +00:00
let result = false ;
_ . forEach ( nonInternalConfs , confTag => {
if ( _ . has ( config . messageConferences [ confTag ] , 'areas' ) &&
2016-09-20 03:28:21 +00:00
Object . keys ( config . messageConferences [ confTag ] . areas ) > 0 )
2018-06-22 05:15:04 +00:00
{
result = true ;
return false ; // stop iteration
}
} ) ;
2016-09-20 03:28:21 +00:00
2018-06-22 05:15:04 +00:00
return result ;
2016-02-03 04:35:59 +00:00
}
2018-06-14 03:02:00 +00:00
function mergeValidateAndFinalize ( config , cb ) {
2018-06-22 05:15:04 +00:00
async . waterfall (
[
function mergeWithDefaultConfig ( callback ) {
const mergedConfig = _ . mergeWith (
getDefaultConfig ( ) ,
config , ( conf1 , conf2 ) => {
// Arrays should always concat
if ( _ . isArray ( conf1 ) ) {
// :TODO: look for collisions & override dupes
return conf1 . concat ( conf2 ) ;
}
}
) ;
return callback ( null , mergedConfig ) ;
} ,
function validate ( mergedConfig , callback ) {
//
// Various sections must now exist in config
//
// :TODO: Logic is broken here:
if ( hasMessageConferenceAndArea ( mergedConfig ) ) {
return callback ( Errors . MissingConfig ( 'Please create at least one message conference and area!' ) ) ;
}
return callback ( null , mergedConfig ) ;
} ,
function setIt ( mergedConfig , callback ) {
// :TODO: .config property is to be deprecated once conversions are done
exports . config = currentConfiguration = mergedConfig ;
exports . get = ( ) => currentConfiguration ;
return callback ( null ) ;
}
] ,
err => {
if ( cb ) {
return cb ( err ) ;
}
}
) ;
2018-06-14 03:02:00 +00:00
}
function init ( configPath , options , cb ) {
2018-06-22 05:15:04 +00:00
if ( ! cb && _ . isFunction ( options ) ) {
cb = options ;
options = { } ;
}
const changed = ( { fileName , fileRoot } ) => {
const reCachedPath = paths . join ( fileRoot , fileName ) ;
ConfigCache . getConfig ( reCachedPath , ( err , config ) => {
if ( ! err ) {
mergeValidateAndFinalize ( config ) ;
}
} ) ;
} ;
const ConfigCache = require ( './config_cache.js' ) ;
const getConfigOptions = {
filePath : configPath ,
noWatch : options . noWatch ,
} ;
if ( ! options . noWatch ) {
getConfigOptions . callback = changed ;
}
ConfigCache . getConfigWithOptions ( getConfigOptions , ( err , config ) => {
if ( err ) {
return cb ( err ) ;
}
return mergeValidateAndFinalize ( config , cb ) ;
} ) ;
2015-04-19 08:13:13 +00:00
}
2014-10-17 02:21:06 +00:00
2015-04-19 08:13:13 +00:00
function getDefaultPath ( ) {
2018-06-22 05:15:04 +00:00
// e.g. /enigma-bbs-install-path/config/
return './config/' ;
2015-04-19 08:13:13 +00:00
}
2014-10-17 02:21:06 +00:00
2015-04-19 08:13:13 +00:00
function getDefaultConfig ( ) {
2018-06-22 05:15:04 +00:00
return {
general : {
boardName : 'Another Fine ENiGMA½ BBS' ,
2015-10-22 04:51:35 +00:00
2018-06-22 05:15:04 +00:00
closedSystem : false , // is the system closed to new users?
2015-10-22 18:22:03 +00:00
2018-06-22 05:15:04 +00:00
loginAttempts : 3 ,
2015-12-11 20:58:58 +00:00
2018-06-22 05:15:04 +00:00
menuFile : 'menu.hjson' , // Override to use something else, e.g. demo.hjson. Can be a full path (defaults to ./config)
promptFile : 'prompt.hjson' , // Override to use soemthing else, e.g. myprompt.hjson. Can be a full path (defaults to ./config)
} ,
2014-10-17 02:21:06 +00:00
2018-06-22 05:15:04 +00:00
// :TODO: see notes below about 'theme' section - move this!
preLoginTheme : 'luciano_blocktronics' ,
2014-10-17 02:21:06 +00:00
2018-06-22 05:15:04 +00:00
users : {
usernameMin : 2 ,
usernameMax : 16 , // Note that FidoNet wants 36 max
usernamePattern : '^[A-Za-z0-9~!@#$%^&*()\\-\\_+ ]+$' ,
2015-12-24 18:51:49 +00:00
2018-06-22 05:15:04 +00:00
passwordMin : 6 ,
passwordMax : 128 ,
badPassFile : paths . join ( _ _dirname , '../misc/10_million_password_list_top_10000.txt' ) , // https://github.com/danielmiessler/SecLists
2015-12-24 18:51:49 +00:00
2018-06-22 05:15:04 +00:00
realNameMax : 32 ,
locationMax : 32 ,
affilsMax : 32 ,
emailMax : 255 ,
webMax : 255 ,
2015-12-24 18:51:49 +00:00
2018-06-22 05:15:04 +00:00
requireActivation : false , // require SysOp activation? false = auto-activate
2015-08-21 04:29:16 +00:00
2018-06-22 05:15:04 +00:00
groups : [ 'users' , 'sysops' ] , // built in groups
defaultGroups : [ 'users' ] , // default groups new users belong to
2015-10-22 17:04:50 +00:00
2018-06-22 05:15:04 +00:00
newUserNames : [ 'new' , 'apply' ] , // Names reserved for applying
2015-10-28 03:12:55 +00:00
2018-06-22 05:15:04 +00:00
badUserNames : [
'sysop' , 'admin' , 'administrator' , 'root' , 'all' ,
'areamgr' , 'filemgr' , 'filefix' , 'areafix' , 'allfix'
] ,
} ,
2015-04-17 04:29:53 +00:00
2018-06-22 05:15:04 +00:00
// :TODO: better name for "defaults"... which is redundant here!
/ *
2015-09-09 04:08:45 +00:00
Concept
"theme" : {
"default" : "defaultThemeName" , // or "*"
"preLogin" : "*" ,
"passwordChar" : "*" ,
...
}
* /
2018-06-22 05:15:04 +00:00
defaults : {
theme : 'luciano_blocktronics' ,
passwordChar : '*' , // TODO: move to user ?
dateFormat : {
short : 'MM/DD/YYYY' ,
long : 'ddd, MMMM Do, YYYY' ,
} ,
timeFormat : {
short : 'h:mm a' ,
} ,
dateTimeFormat : {
short : 'MM/DD/YYYY h:mm a' ,
long : 'ddd, MMMM Do, YYYY, h:mm a' ,
}
} ,
menus : {
cls : true , // Clear screen before each menu by default?
} ,
paths : {
config : paths . join ( _ _dirname , './../config/' ) ,
mods : paths . join ( _ _dirname , './../mods/' ) ,
loginServers : paths . join ( _ _dirname , './servers/login/' ) ,
contentServers : paths . join ( _ _dirname , './servers/content/' ) ,
scannerTossers : paths . join ( _ _dirname , './scanner_tossers/' ) ,
mailers : paths . join ( _ _dirname , './mailers/' ) ,
art : paths . join ( _ _dirname , './../art/general/' ) ,
themes : paths . join ( _ _dirname , './../art/themes/' ) ,
logs : paths . join ( _ _dirname , './../logs/' ) , // :TODO: set up based on system, e.g. /var/logs/enigmabbs or such
db : paths . join ( _ _dirname , './../db/' ) ,
modsDb : paths . join ( _ _dirname , './../db/mods/' ) ,
dropFiles : paths . join ( _ _dirname , './../dropfiles/' ) , // + "/node<x>/
misc : paths . join ( _ _dirname , './../misc/' ) ,
} ,
loginServers : {
telnet : {
port : 8888 ,
enabled : true ,
firstMenu : 'telnetConnected' ,
} ,
ssh : {
port : 8889 ,
enabled : false , // default to false as PK/pass in config.hjson are required
//
// Private key in PEM format
//
// Generating your PK:
// > openssl genrsa -des3 -out ./config/ssh_private_key.pem 2048
//
// Then, set servers.ssh.privateKeyPass to the password you use above
// in your config.hjson
//
privateKeyPem : paths . join ( _ _dirname , './../config/ssh_private_key.pem' ) ,
firstMenu : 'sshConnected' ,
firstMenuNewUser : 'sshConnectedNewUser' ,
} ,
webSocket : {
ws : {
// non-secure ws://
enabled : false ,
port : 8810 ,
} ,
wss : {
// secure ws://
// must provide valid certPem and keyPem
enabled : false ,
port : 8811 ,
certPem : paths . join ( _ _dirname , './../config/https_cert.pem' ) ,
keyPem : paths . join ( _ _dirname , './../config/https_cert_key.pem' ) ,
} ,
} ,
} ,
contentServers : {
web : {
domain : 'another-fine-enigma-bbs.org' ,
staticRoot : paths . join ( _ _dirname , './../www' ) ,
resetPassword : {
//
// The following templates have these variables available to them:
//
// * %BOARDNAME% : Name of BBS
// * %USERNAME% : Username of whom to reset password
// * %TOKEN% : Reset token
// * %RESET_URL% : In case of email, the link to follow for reset. In case of landing page,
// URL to POST submit reset form.
// templates for pw reset *email*
resetPassEmailText : paths . join ( _ _dirname , '../misc/reset_password_email.template.txt' ) , // plain text version
resetPassEmailHtml : paths . join ( _ _dirname , '../misc/reset_password_email.template.html' ) , // HTML version
// tempalte for pw reset *landing page*
//
resetPageTemplate : paths . join ( _ _dirname , './../www/reset_password.template.html' ) ,
} ,
http : {
enabled : false ,
port : 8080 ,
} ,
https : {
enabled : false ,
port : 8443 ,
certPem : paths . join ( _ _dirname , './../config/https_cert.pem' ) ,
keyPem : paths . join ( _ _dirname , './../config/https_cert_key.pem' ) ,
}
}
} ,
infoExtractUtils : {
Exiftool2Desc : {
cmd : ` ${ _ _dirname } /../util/exiftool2desc.js ` , // ensure chmod +x
} ,
Exiftool : {
cmd : 'exiftool' ,
args : [
'-charset' , 'utf8' , '{filePath}' ,
// exclude the following:
'--directory' , '--filepermissions' , '--exiftoolversion' , '--filename' , '--filesize' ,
'--filemodifydate' , '--fileaccessdate' , '--fileinodechangedate' , '--createdate' , '--modifydate' ,
'--metadatadate' , '--xmptoolkit'
]
} ,
XDMS2Desc : {
// http://manpages.ubuntu.com/manpages/trusty/man1/xdms.1.html
cmd : 'xdms' ,
args : [ 'd' , '{filePath}' ]
} ,
XDMS2LongDesc : {
// http://manpages.ubuntu.com/manpages/trusty/man1/xdms.1.html
cmd : 'xdms' ,
args : [ 'f' , '{filePath}' ]
}
} ,
fileTypes : {
//
// File types explicitly known to the system. Here we can configure
// information extraction, archive treatment, etc.
//
// MIME types can be found in mime-db: https://github.com/jshttp/mime-db
//
// Resources for signature/magic bytes:
// * http://www.garykessler.net/library/file_sigs.html
//
//
// :TODO: text/x-ansi -> SAUCE extraction for .ans uploads
// :TODO: textual : bool -- if text, we can view.
// :TODO: asText : { cmd, args[] } -> viewable text
//
// Audio
//
'audio/mpeg' : {
desc : 'MP3 Audio' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
'application/pdf' : {
desc : 'Adobe PDF' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
//
// Video
//
'video/mp4' : {
desc : 'MPEG Video' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
'video/x-matroska ' : {
desc : 'Matroska Video' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
'video/x-msvideo' : {
desc : 'Audio Video Interleave' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
//
// Images
//
'image/jpeg' : {
desc : 'JPEG Image' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
'image/png' : {
desc : 'Portable Network Graphic Image' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
'image/gif' : {
desc : 'Graphics Interchange Format Image' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
'image/webp' : {
desc : 'WebP Image' ,
shortDescUtil : 'Exiftool2Desc' ,
longDescUtil : 'Exiftool' ,
} ,
//
// Archives
//
'application/zip' : {
desc : 'ZIP Archive' ,
sig : '504b0304' ,
offset : 0 ,
archiveHandler : '7Zip' ,
} ,
/ *
2017-08-19 21:24:42 +00:00
'application/x-cbr' : {
desc : 'Comic Book Archive' ,
sig : '504b0304' ,
} ,
* /
2018-06-22 05:15:04 +00:00
'application/x-arj' : {
desc : 'ARJ Archive' ,
sig : '60ea' ,
offset : 0 ,
archiveHandler : 'Arj' ,
} ,
'application/x-rar-compressed' : {
desc : 'RAR Archive' ,
sig : '526172211a0700' ,
offset : 0 ,
archiveHandler : 'Rar' ,
} ,
'application/gzip' : {
desc : 'Gzip Archive' ,
sig : '1f8b' ,
offset : 0 ,
archiveHandler : 'TarGz' ,
} ,
// :TODO: application/x-bzip
'application/x-bzip2' : {
desc : 'BZip2 Archive' ,
sig : '425a68' ,
offset : 0 ,
archiveHandler : '7Zip' ,
} ,
'application/x-lzh-compressed' : {
desc : 'LHArc Archive' ,
sig : '2d6c68' ,
offset : 2 ,
archiveHandler : 'Lha' ,
} ,
'application/x-lzx' : {
desc : 'LZX Archive' ,
sig : '4c5a5800' ,
offset : 0 ,
archiveHandler : 'Lzx' ,
} ,
'application/x-7z-compressed' : {
desc : '7-Zip Archive' ,
sig : '377abcaf271c' ,
offset : 0 ,
archiveHandler : '7Zip' ,
} ,
//
// Generics that need further mapping
//
'application/octet-stream' : [
{
desc : 'Amiga DISKMASHER' ,
sig : '444d5321' , // DMS!
ext : '.dms' ,
shortDescUtil : 'XDMS2Desc' ,
longDescUtil : 'XDMS2LongDesc' ,
}
]
} ,
archives : {
archivers : {
'7Zip' : {
compress : {
cmd : '7za' ,
args : [ 'a' , '-tzip' , '{archivePath}' , '{fileList}' ] ,
} ,
decompress : {
cmd : '7za' ,
args : [ 'e' , '-o{extractPath}' , '{archivePath}' ] // :TODO: should be 'x'?
} ,
list : {
cmd : '7za' ,
args : [ 'l' , '{archivePath}' ] ,
entryMatch : '^[0-9]{4}-[0-9]{2}-[0-9]{2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s[A-Za-z\\.]{5}\\s+([0-9]+)\\s+[0-9]+\\s+([^\\r\\n]+)$' ,
} ,
extract : {
cmd : '7za' ,
args : [ 'e' , '-o{extractPath}' , '{archivePath}' , '{fileList}' ] ,
} ,
} ,
Lha : {
//
// 'lha' command can be obtained from:
// * apt-get: lhasa
//
// (compress not currently supported)
//
decompress : {
cmd : 'lha' ,
args : [ '-efw={extractPath}' , '{archivePath}' ] ,
} ,
list : {
cmd : 'lha' ,
args : [ '-l' , '{archivePath}' ] ,
entryMatch : '^[\\[a-z\\]]+(?:\\s+[0-9]+\\s+[0-9]+|\\s+)([0-9]+)\\s+[0-9]{2}\\.[0-9]\\%\\s+[A-Za-z]{3}\\s+[0-9]{1,2}\\s+[0-9]{4}\\s+([^\\r\\n]+)$' ,
} ,
extract : {
cmd : 'lha' ,
args : [ '-efw={extractPath}' , '{archivePath}' , '{fileList}' ]
}
} ,
Lzx : {
//
// 'unlzx' command can be obtained from:
// * Debian based: https://launchpad.net/~rzr/+archive/ubuntu/ppa/+build/2486127 (amd64/x86_64)
// * RedHat: https://fedora.pkgs.org/28/rpm-sphere/unlzx-1.1-4.1.x86_64.rpm.html
// * Source: http://xavprods.free.fr/lzx/
//
decompress : {
cmd : 'unlzx' ,
// unzlx doesn't have a output dir option, but we'll cwd to the temp output dir first
args : [ '-x' , '{archivePath}' ] ,
} ,
list : {
cmd : 'unlzx' ,
args : [ '-v' , '{archivePath}' ] ,
entryMatch : '^\\s+([0-9]+)\\s+[^\\s]+\\s+[0-9]{2}:[0-9]{2}:[0-9]{2}\\s+[0-9]{1,2}-[a-z]{3}-[0-9]{4}\\s+[a-z\\-]+\\s+\\"([^"]+)\\"$' ,
}
} ,
Arj : {
//
// 'arj' command can be obtained from:
// * apt-get: arj
//
decompress : {
cmd : 'arj' ,
args : [ 'x' , '{archivePath}' , '{extractPath}' ] ,
} ,
list : {
cmd : 'arj' ,
args : [ 'l' , '{archivePath}' ] ,
entryMatch : '^([^\\s]+)\\s+([0-9]+)\\s+[0-9]+\\s[0-9\\.]+\\s+[0-9]{2}\\-[0-9]{2}\\-[0-9]{2}\\s[0-9]{2}\\:[0-9]{2}\\:[0-9]{2}\\s+(?:[^\\r\\n]+)$' ,
entryGroupOrder : { // defaults to { byteSize : 1, fileName : 2 }
fileName : 1 ,
byteSize : 2 ,
}
} ,
extract : {
cmd : 'arj' ,
args : [ 'e' , '{archivePath}' , '{extractPath}' , '{fileList}' ] ,
}
} ,
Rar : {
decompress : {
cmd : 'unrar' ,
args : [ 'x' , '{archivePath}' , '{extractPath}' ] ,
} ,
list : {
cmd : 'unrar' ,
args : [ 'l' , '{archivePath}' ] ,
entryMatch : '^\\s+[\\.A-Z]+\\s+([\\d]+)\\s{2}[0-9]{2}\\-[0-9]{2}\\-[0-9]{2}\\s[0-9]{2}\\:[0-9]{2}\\s{2}([^\\r\\n]+)$' ,
} ,
extract : {
cmd : 'unrar' ,
args : [ 'e' , '{archivePath}' , '{extractPath}' , '{fileList}' ] ,
}
} ,
TarGz : {
decompress : {
cmd : 'tar' ,
args : [ '-xf' , '{archivePath}' , '-C' , '{extractPath}' , '--strip-components=1' ] ,
} ,
list : {
cmd : 'tar' ,
args : [ '-tvf' , '{archivePath}' ] ,
entryMatch : '^[drwx\\-]{10}\\s[A-Za-z0-9\\/]+\\s+([0-9]+)\\s[0-9]{4}\\-[0-9]{2}\\-[0-9]{2}\\s[0-9]{2}\\:[0-9]{2}\\s([^\\r\\n]+)$' ,
} ,
extract : {
cmd : 'tar' ,
args : [ '-xvf' , '{archivePath}' , '-C' , '{extractPath}' , '{fileList}' ] ,
}
}
} ,
} ,
fileTransferProtocols : {
//
// See http://www.synchro.net/docs/sexyz.txt for information on SEXYZ
//
zmodem8kSexyz : {
name : 'ZModem 8k (SEXYZ)' ,
type : 'external' ,
sort : 1 ,
external : {
// :TODO: Look into shipping sexyz binaries or at least hosting them somewhere for common systems
sendCmd : 'sexyz' ,
sendArgs : [ '-telnet' , '-8' , 'sz' , '@{fileListPath}' ] ,
recvCmd : 'sexyz' ,
recvArgs : [ '-telnet' , '-8' , 'rz' , '{uploadDir}' ] ,
recvArgsNonBatch : [ '-telnet' , '-8' , 'rz' , '{fileName}' ] ,
}
} ,
xmodemSexyz : {
name : 'XModem (SEXYZ)' ,
type : 'external' ,
sort : 3 ,
external : {
sendCmd : 'sexyz' ,
sendArgs : [ '-telnet' , 'sX' , '@{fileListPath}' ] ,
recvCmd : 'sexyz' ,
recvArgsNonBatch : [ '-telnet' , 'rC' , '{fileName}' ]
}
} ,
ymodemSexyz : {
name : 'YModem (SEXYZ)' ,
type : 'external' ,
sort : 4 ,
external : {
sendCmd : 'sexyz' ,
sendArgs : [ '-telnet' , 'sY' , '@{fileListPath}' ] ,
recvCmd : 'sexyz' ,
recvArgs : [ '-telnet' , 'ry' , '{uploadDir}' ] ,
}
} ,
zmodem8kSz : {
name : 'ZModem 8k' ,
type : 'external' ,
sort : 2 ,
external : {
sendCmd : 'sz' , // Avail on Debian/Ubuntu based systems as the package "lrzsz"
sendArgs : [
// :TODO: try -q
'--zmodem' , '--try-8k' , '--binary' , '--restricted' , '{filePaths}'
] ,
recvCmd : 'rz' , // Avail on Debian/Ubuntu based systems as the package "lrzsz"
recvArgs : [
'--zmodem' , '--binary' , '--restricted' , '--keep-uppercase' , // dumps to CWD which is set to {uploadDir}
] ,
// :TODO: can we not just use --escape ?
escapeTelnet : true , // set to true to escape Telnet codes such as IAC
}
}
} ,
messageAreaDefaults : {
//
// The following can be override per-area as well
//
maxMessages : 1024 , // 0 = unlimited
maxAgeDays : 0 , // 0 = unlimited
} ,
messageConferences : {
system _internal : {
name : 'System Internal' ,
desc : 'Built in conference for private messages, bulletins, etc.' ,
areas : {
private _mail : {
name : 'Private Mail' ,
desc : 'Private user to user mail/email' ,
maxExternalSentAgeDays : 30 , // max external "outbox" item age
} ,
local _bulletin : {
name : 'System Bulletins' ,
desc : 'Bulletin messages for all users' ,
}
}
}
} ,
scannerTossers : {
ftn _bso : {
paths : {
outbound : paths . join ( _ _dirname , './../mail/ftn_out/' ) ,
inbound : paths . join ( _ _dirname , './../mail/ftn_in/' ) ,
secInbound : paths . join ( _ _dirname , './../mail/ftn_secin/' ) ,
reject : paths . join ( _ _dirname , './../mail/reject/' ) , // bad pkt, bundles, TIC attachments that fail any check, etc.
//outboundNetMail : paths.join(__dirname, './../mail/ftn_netmail_out/'),
// set 'retain' to a valid path to keep good pkt files
} ,
//
// Packet and (ArcMail) bundle target sizes are just that: targets.
// Actual sizes may be slightly larger when we must place a full
// PKT contents *somewhere*
//
packetTargetByteSize : 512000 , // 512k, before placing messages in a new pkt
bundleTargetByteSize : 2048000 , // 2M, before creating another archive
packetMsgEncoding : 'utf8' , // default packet encoding. Override per node if desired.
packetAnsiMsgEncoding : 'cp437' , // packet encoding for *ANSI ART* messages
tic : {
secureInOnly : true , // only bring in from secure inbound (|secInbound| path, password protected)
uploadBy : 'ENiGMA TIC' , // default upload by username (override @ network)
allowReplace : false , // use "Replaces" TIC field
descPriority : 'diz' , // May be diz=.DIZ/etc., or tic=from TIC Ldesc
}
}
} ,
fileBase : {
// areas with an explicit |storageDir| will be stored relative to |areaStoragePrefix|:
areaStoragePrefix : paths . join ( _ _dirname , './../file_base/' ) ,
maxDescFileByteSize : 471859 , // ~1/4 MB
maxDescLongFileByteSize : 524288 , // 1/2 MB
fileNamePatterns : {
// These are NOT case sensitive
// FILE_ID.DIZ - https://en.wikipedia.org/wiki/FILE_ID.DIZ
// Some groups include a FILE_ID.ANS. We try to use that over FILE_ID.DIZ if available.
desc : [
'^[^/\]*FILE_ID\.ANS$' , '^[^/\]*FILE_ID\.DIZ$' , '^[^/\]*DESC\.SDI$' , '^[^/\]*DESCRIPT\.ION$' , '^[^/\]*FILE\.DES$' , '^[^/\]*FILE\.SDI$' , '^[^/\]*DISK\.ID$' // eslint-disable-line no-useless-escape
] ,
// common README filename - https://en.wikipedia.org/wiki/README
descLong : [
'^[^/\]*\.NFO$' , '^[^/\]*README\.1ST$' , '^[^/\]*README\.NOW$' , '^[^/\]*README\.TXT$' , '^[^/\]*READ\.ME$' , '^[^/\]*README$' , '^[^/\]*README\.md$' // eslint-disable-line no-useless-escape
] ,
} ,
yearEstPatterns : [
//
// Patterns should produce the year in the first submatch.
// The extracted year may be YY or YYYY
//
'\\b((?:[1-2][0-9][0-9]{2}))[\\-\\/\\.][0-3]?[0-9][\\-\\/\\.][0-3]?[0-9]\\b' , // yyyy-mm-dd, yyyy/mm/dd, ...
'\\b[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[1-2][0-9][0-9]{2}))\\b' , // mm/dd/yyyy, mm.dd.yyyy, ...
'\\b((?:[1789][0-9]))[\\-\\/\\.][0-3]?[0-9][\\-\\/\\.][0-3]?[0-9]\\b' , // yy-mm-dd, yy-mm-dd, ...
'\\b[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[1789][0-9]))\\b' , // mm-dd-yy, mm/dd/yy, ...
//'\\b((?:[1-2][0-9][0-9]{2}))[\\-\\/\\.][0-3]?[0-9][\\-\\/\\.][0-3]?[0-9]|[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b', // yyyy-mm-dd, m/d/yyyy, mm-dd-yyyy, etc.
//"\\b('[1789][0-9])\\b", // eslint-disable-line quotes
'\\b[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b' ,
'\\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december),?\\s[0-9]+(?:st|nd|rd|th)?,?\\s((?:[0-9]{2})?[0-9]{2})\\b' , // November 29th, 1997
'\\(((?:19|20)[0-9]{2})\\)' , // (19xx) or (20xx) -- with parens -- do this before 19xx 20xx such that this has priority
'\\b((?:19|20)[0-9]{2})\\b' , // simple 19xx or 20xx with word boundaries
'\\b\'([17-9][0-9])\\b' , // '95, '17, ...
// :TODO: DD/MMM/YY, DD/MMMM/YY, DD/MMM/YYYY, etc.
] ,
web : {
path : '/f/' ,
routePath : '/f/[a-zA-Z0-9]+$' ,
expireMinutes : 1440 , // 1 day
} ,
//
// File area storage location tag/value pairs.
// Non-absolute paths are relative to |areaStoragePrefix|.
//
storageTags : {
sys _msg _attach : 'sys_msg_attach' ,
sys _temp _download : 'sys_temp_download' ,
} ,
areas : {
system _message _attachment : {
name : 'System Message Attachments' ,
desc : 'File attachments to messages' ,
storageTags : [ 'sys_msg_attach' ] ,
} ,
system _temporary _download : {
name : 'System Temporary Downloads' ,
desc : 'Temporary downloadables' ,
storageTags : [ 'sys_temp_download' ] ,
}
}
} ,
eventScheduler : {
events : {
trimMessageAreas : {
// may optionally use [or ]@watch:/path/to/file
schedule : 'every 24 hours' ,
// action:
// - @method:path/to/module.js:theMethodName
// (path is relative to engima base dir)
//
// - @execute:/path/to/something/executable.sh
//
action : '@method:core/message_area.js:trimMessageAreasScheduledEvent' ,
} ,
updateFileAreaStats : {
schedule : 'every 1 hours' ,
action : '@method:core/file_base_area.js:updateAreaStatsScheduledEvent' ,
} ,
forgotPasswordMaintenance : {
schedule : 'every 24 hours' ,
action : '@method:core/web_password_reset.js:performMaintenanceTask' ,
args : [ '24 hours' ] // items older than this will be removed
} ,
//
// Enable the following entry in your config.hjson to periodically create/update
// DESCRIPT.ION files for your file base
//
/ *
2018-03-13 04:18:09 +00:00
updateDescriptIonFiles : {
2018-03-13 04:55:10 +00:00
schedule : 'on the last day of the week' ,
2018-03-13 04:18:09 +00:00
action : '@method:core/file_base_list_export.js:updateFileBaseDescFilesScheduledEvent' ,
2016-06-20 03:09:45 +00:00
}
2018-03-14 00:59:47 +00:00
* /
2018-06-22 05:15:04 +00:00
}
} ,
misc : {
preAuthIdleLogoutSeconds : 60 * 3 , // 3m
idleLogoutSeconds : 60 * 6 , // 6m
} ,
logging : {
level : 'debug' ,
rotatingFile : { // set to 'disabled' or false to disable
type : 'rotating-file' ,
fileName : 'enigma-bbs.log' ,
period : '1d' ,
count : 3 ,
level : 'debug' ,
}
// :TODO: syslog - https://github.com/mcavage/node-bunyan-syslog
} ,
debug : {
assertsEnabled : false ,
}
} ;
2015-04-19 08:13:13 +00:00
}