ios3
6/26/2018 - 1:07 PM

ota.js

var host			=		"CHANGEME";
//var host			=		"http://localhost:5000/";
var express			=		require("express");
var multer			=		require('multer');
var app				=		express();
var done			=		false;
var uploadPath		=		host+"appbox/uploads/";
var uploadLocalPath	=		__dirname + "/public/appbox/uploads/";
var fs				=		require('fs');
var appsJsonFile	=		__dirname + "/public/appbox/apps.json";
var appsHtmlFile	=		__dirname + "/public/appbox/appbox.html";
var http			=		require('http');
app.use(express.static(__dirname + '/public'));
 
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

app.set('port', (process.env.PORT || 5000));

app.use(multer({ dest: './public/appbox/uploads/',
	rename: function (fieldname, filename) {
		return filename.replace(/\W+/g, '-').toLowerCase() + Date.now()
	},
	limits: {
		fieldNameSize: 200,
		files: 2,
		fields: 5
	},
	onFileUploadStart: function (file) {
		console.log(file.originalname + ' is starting ...')
	},
	onFileUploadComplete: function (file) {
		console.log(file.fieldname + ' uploaded to  ' + file.path)
		done = true;
	}
}));

app.get('/',function(req,res){
	var appsObj = getAppsJson();
	res.render('index', { title: 'Apps',appsObj:appsObj,host:host });
});

app.get('/getManifest',function(req,res){
	//host = req.protocol + "://" + req.headers.host + "/";
	res.set('Content-Type', 'application/x-plist');
	var id = req.query.appId;
	var appsObj = getAppsJson();
	appsObj[id].host = host;
	res.render('manifest', appsObj[id]);
});

app.post('/api/addApp',function(req,res){
	if(done == true){
		var appObj = req.files;
		appObj["bundleId"] = req.body.bundleId;
		appObj["appName"] = req.body.appName;
		appObj["ipaFile"] = appObj["ipaFile"].name;
		appObj["provisionFile"] = appObj["provisionFile"].name;
		addAndNewApp(appObj["bundleId"],appObj["appName"],appObj["ipaFile"],appObj["provisionFile"]);
		res.redirect('/');
	}
});

function addAndNewApp(bundleId,appName,ipaFile,provisionFile){
	var appObj = {};
	var date = Date.now();
	var id = date.toString();
	appObj["id"] = id;
	appObj["bundleId"] = bundleId;
	appObj["appName"] = appName;
	appObj["ipaFile"] = ipaFile;
	appObj["provisionFile"] = provisionFile;
	addAppToJsonFile(appObj);
	fs.writeFileSync(uploadLocalPath+"manifest"+id+".plist", getManifestText(appObj));
}

app.get('/api/remove',function(req,res){
	//res.writeHead(200, {'Content-Type': 'application/json'});
	removeAppById( req.query.appId );
	//res.end( JSON.stringify( true ) );
	res.redirect('/');
});

function getAppsHtml(appsObj){
	var html = "<html>\n"+
	"  <head>\n"+
	"    <title>Apps list</title>\n"+
	"  </head>\n"+
	"  <body>\n"+
	"  <a href='/'>Add new app page</a>\n"+
	"  <table width='100%' border='1'>\n"+
	"  	<tr>\n"+
	"		<td>\n"+
	"			Name\n"+
	"		</td>\n"+
	"		<td>\n"+
	"			Provision\n"+
	"		</td>\n"+
	"		<td>\n"+
	"			Download link\n"+
	"		</td>\n"+
	"		<td>\n"+
	"			\n"+
	"		</td>\n"+
	"	</tr>\n";
	var ids = Object.keys(appsObj);
	for(var i=0; i< ids.length; i++){
		var id = ids[i];
		html = html +"<tr>\n"+
		"			<td>\n"+
						appsObj[id].appName+
		"			</td>\n"+
		"			<td>\n"+
		"				<a href='"+ uploadPath + appsObj[id].provisionFile+"'>provision file</a>\n"+
		"			</td>\n"+
		"			<td>\n"+
		"				<a href='itms-services://?action=download-manifest&url="+uploadPath+"/manifest"+appsObj[id].id+".plist'>download ipa</a>\n"+
		"			</td>\n"+
		"			<td>\n"+
		"				<a href='/api/remove?appId="+id+"'>remove</a>\n"+
		"			</td>\n"+
		"		</tr>\n"+
		"		\n";
	}
	html = html+ "  </table>\n"+
	"</html>\n";
	
	return html;
}


function getManifestText(appObj){
	return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"+
"<plist version=\"1.0\">"+
"<dict>"+
"	<key>items</key>"+
"	<array>"+
"		<dict>"+
"			<key>assets</key>"+
"			<array>"+
"				<dict>"+
"					<key>kind</key>"+
"					<string>software-package</string>"+
"					<key>url</key>"+
"					<string>"+uploadPath+appObj.ipaFile+"</string>"+
"				</dict>"+
"				<dict>"+
"					<key>kind</key>"+
"					<string>full-size-image</string>"+
"					<key>needs-shine</key>"+
"					<true/>"+
"					<key>url</key>"+
"					<string>"+host+"iOS-512.png</string>"+
"				</dict>"+
"				<dict>"+
"					<key>kind</key>"+
"					<string>display-image</string>"+
"					<key>needs-shine</key>"+
"					<true/>"+
"					<key>url</key>"+
"					<string>"+host+"iOS-57.png</string>"+
"				</dict>"+
"			</array>"+
"			<key>metadata</key>"+
"			<dict>"+
"				<key>bundle-identifier</key>"+
"				<string>"+appObj.bundleId+"</string>"+
"				<key>kind</key>"+
"				<string>software</string>"+
"				<key>subtitle</key>"+
"				<string>"+appObj.appName+"</string>"+
"				<key>title</key>"+
"				<string>"+appObj.appName+"</string>"+
"			</dict>"+
"		</dict>"+
"	</array>"+
"</dict>"+
"</plist>";
}

function removeAppById(appId){
	var appsObjNew = {};
	if (fs.existsSync(appsJsonFile)) {
		var appsObjOld = getAppsJson();
		var ids = Object.keys(appsObjOld);
		for(var i=0; i < ids.length;i++){
			var oldId = ids[i];
			if(oldId != appId){
				appsObjNew[oldId] = appsObjOld[oldId];
			}
		}
		saveAppsObj(appsObjNew);
	}
}

// function removeFilesOfAppId(appId){
// 	fs.unlinkSync()
// }

function addAppToJsonFile(appObj){
	var appsObj = {};
	if (fs.existsSync(appsJsonFile)) {
		appsObj = getAppsJson();
	}
	appsObj[appObj.id] = appObj ;
	saveAppsObj(appsObj)
}

function saveAppsObj(appsObj){
	fs.writeFileSync(appsJsonFile, JSON.stringify(appsObj, null, 4));
	fs.writeFileSync(appsHtmlFile, getAppsHtml(appsObj)); 
}

function getAppsJson(){
	return JSON.parse(fs.readFileSync(appsJsonFile, 'utf8'));
}

var isCommand = false;
console.log("process.argv.length:"+process.argv.length);
process.argv.forEach(function (val, index, array) {
  console.log(index + ': ' + val);
  if(index == 2 && val == "genlinks"){
  	isCommand = true;
  }
});

if(!isCommand){
	app.listen(app.get('port'), function() {
		console.log("Node app is running at localhost:" + app.get('port'));
	});
}else{
	addAndNewApp(
		process.argv[3],  //bundleId,
		process.argv[4],  //appName,
		process.argv[5],  //ipaFile,
		process.argv[6]   //provisionFile
	);
}