2019-10-22 10:57:25 +00:00
|
|
|
load('smbdefs.js');
|
|
|
|
|
2020-02-26 11:54:39 +00:00
|
|
|
// Ansitex specific includes
|
|
|
|
load('ansitex/load/defs.js');
|
|
|
|
load('ansitex/load/funcs.js');
|
|
|
|
|
2019-10-22 10:57:25 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2020-02-26 11:54:39 +00:00
|
|
|
var f = new File(file_cfgname(system.mods_dir,'ansitex/ctrl/videotex.ini'));
|
2019-10-22 10:57:25 +00:00
|
|
|
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
|
2020-02-26 11:54:39 +00:00
|
|
|
result = system.exec('gpgv --keyring '+system.mods_dir+'ansitex/keys/pubring.kbx '+system.temp_dir+'videotex.gpg');
|
2019-10-22 10:57:25 +00:00
|
|
|
|
|
|
|
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
|
2020-02-26 11:54:39 +00:00
|
|
|
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');
|
2019-10-22 10:57:25 +00:00
|
|
|
|
|
|
|
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));
|
|
|
|
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();
|