- feature: add SSID whitelist/blacklist as well as IP based SSID auth - Add user_config_README.md - Update user_config.example.json - Update README.md - update: wtv-1800:/finish-prereg: send tellyscript on relogin if tellyscripts are enabled, and wtv-script-id == 0 (no tellyscript) - Allow definition of custom ServiceVault paths - feature: app.js: add `bind_ip` option to specify an IP to bind to, instead of `0.0.0.0` - feature: custom service logos and better wtv-home:/splash
182 lines
8.5 KiB
JavaScript
182 lines
8.5 KiB
JavaScript
// todo: async
|
|
|
|
var path = require("path");
|
|
|
|
var content_dir = "content/"
|
|
var diskmap_dir = content_dir + "diskmaps/";
|
|
|
|
function generateDownloadList(diskmap_group_data, update_list, diskmap_data) {
|
|
// create WebTV Download List
|
|
|
|
var newest_file_epoch = 0;
|
|
var download_list = '';
|
|
|
|
if (diskmap_data.partition_size) {
|
|
download_list += "CREATE " + diskmap_data.base + "\n";
|
|
download_list += "partition-size: " + diskmap_data.partition_size + "\n\n";
|
|
}
|
|
|
|
download_list += "CREATE-GROUP " + diskmap_group_data + "-UPDATE\n";
|
|
download_list += "state: invalid\n";
|
|
download_list += "base: " + diskmap_data.base + ".GROUP-UPDATE/\n\n";
|
|
|
|
Object.keys(update_list).forEach(function (k) {
|
|
if (parseInt(update_list[k]["Last-modified"]) > newest_file_epoch) newest_file_epoch = parseInt(update_list[k]["Last-modified"]);
|
|
download_list += "DISPLAY " + update_list[k].display + "\n\n";
|
|
download_list += "GET " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
|
download_list += "group: " + diskmap_group_data + "-UPDATE\n";
|
|
download_list += "location: " + service_name + ":/" + update_list[k].location + "\n";
|
|
download_list += "file-permission: r\n"
|
|
download_list += "wtv-checksum: " + update_list[k]["wtv-checksum"] + "\n";
|
|
download_list += "service-source-location: /webtv/content/" + service_name.replace("wtv-","") + "d/" + update_list[k].location + "\n";
|
|
download_list += "client-dest-location: " + update_list[k].file + "\n\n";
|
|
});
|
|
|
|
download_list += "CREATE-GROUP " + diskmap_group_data + "\n";
|
|
download_list += "state: invalid\n";
|
|
download_list += "service-owned: " + (diskmap_data.service_owned || false) + "\n";
|
|
download_list += "base: " + diskmap_data.base + "\n\n";
|
|
|
|
Object.keys(update_list).forEach(function (k) {
|
|
download_list += "DELETE " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
|
download_list += "group: " + diskmap_group_data + "\n\n";
|
|
});
|
|
|
|
Object.keys(update_list).forEach(function (k) {
|
|
download_list += "RENAME " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
|
download_list += "group: " + diskmap_group_data + "-UPDATE\n";
|
|
download_list += "destination-group: " + diskmap_group_data + "\n";
|
|
download_list += "location: " + update_list[k].file.replace(diskmap_data.base, "") + "\n\n";
|
|
});
|
|
|
|
download_list += "DELETE-GROUP " + diskmap_group_data + "-UPDATE\n\n";
|
|
|
|
download_list += "SET-GROUP " + diskmap_group_data + "\n";
|
|
download_list += "state: ok\n";
|
|
download_list += "version: " + newest_file_epoch + "\n";
|
|
download_list += "last-checkup-time: " + new Date().toUTCString().replace("GMT", "+0000") + "\n\n";
|
|
|
|
return download_list;
|
|
}
|
|
|
|
function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgroup = null) {
|
|
// parse webtv post
|
|
var output_data = '';
|
|
var post_data = request_headers.post_data.toString(CryptoJS.enc.Latin1).split("\n");
|
|
var post_data_current_directory = '';
|
|
var post_data_current_file = '';
|
|
var post_data_fileinfo = new Array();
|
|
var post_data_filecount = -1;
|
|
|
|
Object.keys(post_data).forEach(function (k) {
|
|
if (post_data[k] == "") return;
|
|
if (post_data[k].substring(0, 7) == "file://") {
|
|
post_data_current_directory = post_data[k];
|
|
post_data_current_file = post_data[k];
|
|
}
|
|
if (post_data[k].indexOf(":") > 0) {
|
|
var post_data_line = post_data[k].split(": ")
|
|
var post_data_line_name = post_data_line[0];
|
|
post_data_line.shift();
|
|
var post_data_line_data = post_data_line.join(": ");
|
|
|
|
if (!post_data_fileinfo[post_data_filecount]) post_data_fileinfo[post_data_filecount] = new Array();
|
|
|
|
if (post_data_line_name == "Last-modified") {
|
|
post_data_fileinfo[post_data_filecount][post_data_line_name] = (Date.parse(post_data_line_data) / 1000);
|
|
} else if (post_data_line_name == "Content-length") {
|
|
post_data_fileinfo[post_data_filecount][post_data_line_name] = parseInt(post_data_line_data);
|
|
}
|
|
else {
|
|
post_data_fileinfo[post_data_filecount][post_data_line_name] = post_data_line_data;
|
|
}
|
|
} else {
|
|
post_data_filecount++;
|
|
post_data_current_file = post_data_current_directory + post_data[k];
|
|
post_data_fileinfo[post_data_filecount] = new Array();
|
|
post_data_fileinfo[post_data_filecount].file = post_data_current_file
|
|
}
|
|
});
|
|
var wtv_download_list = new Array();
|
|
Object.keys(diskmap_group_data.files).forEach(function (k) {
|
|
if (!diskmap_group_data.files[k].location) diskmap_group_data.files[k].location = diskmap_group_data.location + diskmap_group_data.files[k].file.replace(diskmap_group_data.base, "");
|
|
var post_match_file = null;
|
|
Object.keys(service_vaults).forEach(function (g) {
|
|
if (post_match_file != null) return;
|
|
post_match_file = service_vaults[g] + "/" + service_name + "/" + diskmap_group_data.files[k].location;
|
|
if (!fs.existsSync(post_match_file)) post_match_file = null;
|
|
});
|
|
|
|
var post_match_file_lstat = fs.lstatSync(post_match_file);
|
|
var post_match_result = post_data_fileinfo.find(el => el.file === diskmap_group_data.files[k].file) || null;
|
|
|
|
var post_match_file_data = new Buffer.from(fs.readFileSync(post_match_file, {
|
|
encoding: null,
|
|
flags: 'r'
|
|
}));
|
|
diskmap_group_data.files[k]["Last-modified"] = (post_match_file_lstat.mtime / 1000);
|
|
diskmap_group_data.files[k]["Content-length"] = post_match_file_lstat.size;
|
|
diskmap_group_data.files[k]["wtv-checksum"] = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase();
|
|
if (!diskmap_group_data.files[k].display) diskmap_group_data.files[k].display = diskmap_group_data.display;
|
|
|
|
if (post_match_result) {
|
|
// md5s match, so client doesn't need file
|
|
if (diskmap_group_data.files[k]['wtv-checksum'].toLowerCase() == post_match_result["wtv-checksum"]) return;
|
|
else wtv_download_list.push(diskmap_group_data.files[k]);
|
|
} else {
|
|
wtv_download_list.push(diskmap_group_data.files[k]);
|
|
}
|
|
var diskmap_group_name = (diskmap_subgroup == null) ? diskmap_primary_group : diskmap_primary_group + "-" + diskmap_subgroup;
|
|
output_data = generateDownloadList(diskmap_group_name, wtv_download_list, diskmap_group_data)
|
|
});
|
|
return output_data;
|
|
}
|
|
|
|
if (request_headers.query.diskmap && request_headers.query.group && request_headers.post_data) {
|
|
var diskmap_json_file = null;
|
|
Object.keys(service_vaults).forEach(function (g) {
|
|
if (diskmap_json_file != null) return;
|
|
diskmap_json_file = service_vaults[g] + "/" + service_name + "/" + diskmap_dir + request_headers.query.diskmap + ".json";
|
|
if (!fs.existsSync(diskmap_json_file)) diskmap_json_file = null;
|
|
});
|
|
|
|
if (diskmap_json_file != null) {
|
|
if (fs.lstatSync(diskmap_json_file)) {
|
|
try {
|
|
// read diskmap
|
|
var diskmap_data = JSON.parse(fs.readFileSync(diskmap_json_file).toString());
|
|
if (!diskmap_data[request_headers.query.group]) {
|
|
throw ("Invalid diskmap data (group does not match)");
|
|
}
|
|
data = '';
|
|
diskmap_data = diskmap_data[request_headers.query.group];
|
|
if (!diskmap_data.display) {
|
|
Object.keys(diskmap_data).forEach(function (k) {
|
|
if (diskmap_data[k]) data += processGroup(request_headers.query.group,diskmap_data[k],k);
|
|
});
|
|
} else {
|
|
data = processGroup(request_headers.query.group, diskmap_data);
|
|
}
|
|
|
|
headers = "200 OK\nContent-Type: wtv/download-list";
|
|
} catch (e) {
|
|
var errpage = doErrorPage(400);
|
|
headers = errpage[0];
|
|
data = errpage[1];
|
|
console.log("wtv-update:/sync error", e);
|
|
}
|
|
}
|
|
} else {
|
|
var errpage = doErrorPage(404,"The requested DiskMap does not exist.");
|
|
headers = errpage[0];
|
|
data = errpage[1];
|
|
console.log("wtv-update:/sync error", "could not find diskmap");
|
|
}
|
|
} else {
|
|
var errpage = doErrorPage(400);
|
|
headers = errpage[0];
|
|
data = errpage[1];
|
|
if (zdebug) console.log("wtv-update:/sync error", "missing query arguments");
|
|
}
|
|
|