sbbs/tools/export.js

244 lines
6.0 KiB
JavaScript

load('smbdefs.js');
// ANSItex specific includes
load('ansitex/load/defs.js');
load('ansitex/load/funcs.js');
/**
* Work out which key should be used for a page, or validate if a key used is valid
*
* @param page
* @param signed
* @returns {*}
*/
function getKey(page,signed) {
log(LOG_DEBUG,'+ CHECKING key:'+signed+' for page: '+page);
var f = new File(file_cfgname(system.mods_dir,'ansitex/ctrl/videotex.ini'));
var match = '';
if (f.open("r")) {
var BreakException = {};
// Default Key
var key = f.iniGetValue('prefix','key');
try {
f.iniGetSections("prefix:").forEach(function (prefix) {
var p = prefix.substr(7);
var pk = f.iniGetValue(prefix, 'Key', '');
var re = new RegExp('^' + p, 'g');
// If it was signed, is the key a value one
if (signed && signed.length) {
if (pk === signed) {
//print('SIGNED key is valid:' + signed);
key = signed;
throw BreakException;
}
// Which key should sign this page
} else if (page.toString().match(re) && (p.length > match.length)) {
match = p;
key = pk;
}
});
} catch (e) {
if (e !== BreakException) throw e;
}
}
f.close();
log(LOG_DEBUG,'- key:'+key);
return key;
}
/**
* Export message from message base
*
* @param msgbase
*/
function msgBaseExport(msgbase) {
var ini = new File(msgbase.file+'.ini');
var i=0;
if (ini.open("r")) {
export_ptr=ini.iniGetValue('videotex','export_ptr',0);
ini.close();
} else {
log(LOG_ERROR,'! ERROR: Unable to open INI for ['+msgbase.file+']');
}
// If pointer doesnt exist, reset it from the message base.
if (export_ptr === undefined) {
var f = new File(file_getcase(msgbase.file+'.sbl'));
if (f.open('rb')) {
export_ptr = f.readBin(4);
f.close();
}
}
highest = export_ptr;
var total_msgs = msgbase.total_msgs;
log(LOG_DEBUG,'| msgBaseExport: export_ptr='+export_ptr+'|last_msg='+msgbase.last_msg+'|total_msgs='+total_msgs);
if (msgbase.last_msg >= export_ptr)
i = total_msgs-(msgbase.last_msg-export_ptr);
for (; i<total_msgs; i++) {
if (js.terminated)
break;
var idx = msgbase.get_msg_index(true,i);
if (! idx) {
log(LOG_ERROR,'! ERROR: Reading index of msg offset ['+i+'] : ['+msgbase.error+']');
continue;
}
// Skip message until we get to our last one read.
if (idx.number <= export_ptr)
continue;
if (idx.number > highest)
highest = idx.number;
// Only check messages from Videotex
if (idx.from !== crc16_calc('videotex')) {
log(LOG_DEBUG,'! IGNORING: Message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
// Get the message header
var hdr = msgbase.get_msg_header(true,i);
// Ignore deleted messages
if (hdr.attr&MSG_DELETE) {
log(LOG_DEBUG,'! IGNORING: Deleted message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
// Ignore locally posted messages
if (! hdr.from_net_type) {
log(LOG_DEBUG,'! IGNORING: Local message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
log(LOG_DEBUG,'+ PROCESSING: Message offset ['+i+'] in ['+msgbase.file+'] from ['+hdr.from_net_addr+'] ('+hdr.subject+')');
var body = msgbase.get_msg_body(
/* by_offset: */true,
i,
/* strip Ctrl-A */true,
/* rfc822-encoded: */false,
/* include tails: */false);
t = new File(system.temp_dir+'videotex.gpg');
if (! t.open('w+')) {
log(LOG_ERROR,'! ERROR: Unable to open temp file ['+system.temp_dir+'videotex.gpg'+']');
exit(1);
}
try {
t.write(base64_decode(body));
t.close();
} catch (error) {
log(LOG_ERROR,error);
exit(1);
}
// Check if the signature is good
result = system.exec('gpgv --keyring '+system.mods_dir+'ansitex/keys/pubring.kbx '+system.temp_dir+'videotex.gpg');
if (result !== 0 ) {
log(LOG_ERROR,'! ERROR: Invalid Signature for message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
if (file_exists(system.temp_dir+'videotex.tex'))
file_remove(system.temp_dir+'videotex.tex')
// Check that the signature is allowed to author the frames
result = system.exec('gpg --homedir '+system.mods_dir+'ansitex/keys --batch --status-fd 2 -o '+system.temp_dir+'videotex.tex '+system.temp_dir+'videotex.gpg 2>'+system.temp_dir+'videotex.log');
if (result !== 0 ) {
log(LOG_ERROR,'! ERROR: Failed to extract message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
// Put frame in place.
f = new File(system.temp_dir+'videotex.tex');
if (! f.exists || ! f.open('r')) {
log(LOG_ERROR,'! ERROR: Failed to open frame for message offset ['+i+'] in ['+msgbase.file+']');
exit(1);
}
try {
frame = JSON.parse(f.read());
x = new Frame(0);
frame.render = x.render;
// @todo Figure out how to delete this duplicate code
Object.defineProperty(frame,'page', {
get: function() {return this.frame+this.index}
});
x = null;
} catch (error) {
log(LOG_ERROR,error);
continue;
}
// Get the key that signed the message
f = new File(system.temp_dir+'videotex.log');
if (! f.exists || ! f.open('r')) {
log(LOG_ERROR,'! ERROR: Failed to open gpg log for message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
var signed = '';
while (string = f.readln()) {
var matches = string.match(/\s+GOODSIG\s+.*\<(.*)\>/);
if (matches) {
signed = matches[1];
}
}
f.close();
if (signed !== getKey(frame.frame,signed)) {
log(LOG_ERROR,'! ERROR: Key ['+signed+' is not authorised for message offset ['+i+'] in ['+msgbase.file+']');
continue;
}
// Save the frame.
log(LOG_INFO,'Updating page ['+frame.page+'] from ['+hdr.from_net_addr+'] signed with ['+signed+']');
saveFrame(frame);
}
if (ini.open(file_exists(ini.name) ? 'r+':'w+')) {
ini.iniSetValue('videotex','export_ptr',highest);
ini.close();
} else {
log(LOG_ERROR,'! ERROR: Unable to save to INI for ['+msgbase.file+']');
}
}
var msgbase = new MsgBase(findMsgBase(null).code);
log(LOG_DEBUG,'+ ANSITEX_EXPORT: Open message base in ['+msgbase.file+']');
if (! msgbase.open()) {
log(LOG_ERROR,'! ERROR: Unable to open ['+msgbase.file+']');
exit(-1);
}
msgBaseExport(msgbase);
msgbase.close();