Nginx konfigurációk generálása, egy pull request története

Üdvözlöm, barátaim. A harci szervereimen csodás nginx 2006 óta működik, és évek alatt sok konfigurációt és sablont gyűjtöttem össze. Sokáig dicsértem az nginx-t, és valahogy arra is én ösztönöztem, hogy az nginx hub is megjelenjen a Habr-on, jó móka m/
A barátaim megkértek, hogy hozzak létre nekik egy fejlesztő farmot, és ahelyett, hogy áthoznék nekik a saját specifikus sablonjaimat, eszembe jutott egy érdekes projekt nginxconfig.io, amely a konfigurációkat szétszórja és minden szükséges dolgot előkészít a lets encrypt-hez. Gondoltam, miért ne? Azonban irritált az a tény, hogy az nginxconfig megkér, hogy töltsök le egy zip archívumot a böngészőmből, nem engedve, hogy azonnal letöltsem a szerverre wget/fetch/curl segítségével. Mi ez a képtelenség, miért van szükségem rá a böngészőmben, amikor konzolban a szerveren van rá szükségem? Felháborodva megnéztem a github-on a projekt belső működését, ami a forkhoz és ennek következtében a pull requesthez vezetett. Amiről nem írtam volna, ha nem lenne érdekes 😉

Nginx konfigurációk generálása, egy pull request története

Természetesen, mielőtt beleásnék a forráshoz, megnéztem, honnan tölti le a chrome a generált zip archívumot a konfigurációkkal, és ott egy „blob:” kezdettel rendelkező címet találtam. Már világos volt, hogy a szolgáltatás nem generál semmit, valójában mindezt a js végzi. Valóban, a zip archívumot maga a kliens, a böngésző, a javascript generálja. Tehát a szépsége az, hogy a projekt nginxconfig.io egyszerűen csak elmenthető html oldalként, feltölthető valahova narod.ru és működni fog ) Ez egy nagyon szórakoztató és érdekes megoldás, azonban rettenetesen kényelmetlen a szerverek beállításához, pontosan azért, amire ezt a projektet létrehozták. A böngészőből letölteni a generált archívumot, majd átkonvertálni a szerverre nc segítségével… 2019-ben? Kitűztem magam elé a célt, hogy találjak egy módot, amellyel az elkészített konfigurációt közvetlenül a szerverre tudom letölteni.
A projekt fork után elkezdtem gondolkodni, hogy milyen lehetőségeim vannak. A feladatot nehezítette, hogy nem akartam eltérni attól a feltételtől, hogy a projektnek tiszta front-endnek kell maradnia, bármilyen back-end nélkül. Természetesen a legjobb megoldás az lett volna, ha igénybe veszem a nodejs-t, és arra kényszerítem, hogy generáljon archívumot közvetlen linkek alapján.
Igazából nem sok lehetőség volt. Pontosabban, csak egy ötlet jutott eszembe. Be kell állítanunk a konfigurációkat, és meg kell kapnunk a linket, amelyet be tudunk másolni a szerver konzoljába, hogy megkapjuk a zip archívumot.
Néhány szöveges fájl a megkapott zip archívumban mindössze néhány kilobájtot nyomott. Nyilvánvaló megoldás volt, hogy ki kell nyerni a base64 sztringet az előállított zip archívumból és be kell tenni a vágólapra, míg a szerveren parancssorban futtatjuk.

echo 'base64string' | base64 --decode > config.zip

Létrehozhatnánk ezt a zip fájlt.

nginxconfig.io AngularJS-ben íródott, elképzelni sem tudom, mennyi kilométernyi kódra lett volna szükség, ha a szerző nem egy reaktív js keretrendszert választott volna. Viszont jól tudom, mennyivel egyszerűbb és szebben meg lehetett volna valósítani ezt VueJS-ben, de ez már egy teljesen más téma.
A projekt forrásaiban látjuk a zip archívum generálási metódust:

$scope.downloadZip = function() {
	var zip = new JSZip();

	var sourceCodes = $window.document.querySelectorAll('main .file .code.source');

	for (var i = 0; i < sourceCodes.length; i++) {
		var sourceCode = sourceCodes[i];

		var name	= sourceCode.dataset.filename;
		var content	= sourceCode.children[0].children[0].innerText;

		if (!$scope.isSymlink() && name.match(/^sites-available\/)) {
			name = name.replace(/^sites-available\/, 'sites-enabled/');
		}

		zip.file(name, content);

		if (name.match(/^sites-available\/)) {
			zip.file(name.replace(/^sites-available\/, 'sites-enabled/'), '..\/ ' + name, {
				unixPermissions: parseInt('120755', 8),
			});
		}
	}

	zip.generateAsync({
		type: 'blob',
		platform: 'UNIX',
	}).then(function(content) {
		saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_zip',
	});
};

Minden elég egyszerű, a könyvtár segítségével. jszip zip-t hoz létre, ahová a konfigurációs fájlok kerülnek. A zip archívum létrehozása után a js átkonvertálja azt a böngésző számára a könyvtár segítségével. FileSaver.js:

saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');

ahol a content a megkapott zip archívum blob objektuma.

Rendben, mindössze annyit kellett tennem, hogy hozzáadok még egy gombot mellé, és ha rákattintok, ne mentse el a megkapott zip archívumot a böngészőbe, hanem szerezze meg belőle a base64 kódot. Kicsit variálva, két metódust kaptam az egy helyett, a downloadZip mellett:

$scope.downloadZip = function() {
	generateZip(function (content) {
		saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_zip',
	});
};
$scope.downloadBase64 = function() {
	generateZip(function (content) {
		var reader = new FileReader();
		reader.readAsDataURL(content);
		reader.onloadend = function() {
			var base64 = reader.result.replace(/^data:.+;base64,/, '');
			// a base64 változóban ott van a szükséges zip archívum a base64 sztring formájában
		}
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_base64',
	});
};

Ahogy észrevehettétek, a zip archívum generálását átvittem egy privát generateZip metódusba, és mivel ez AngularJS, valamint a szerző is a callback-ek mellett érvelt, nem valósítottam meg ígéretek (promises) segítségével. A downloadZip még mindig a saveAs-t adta ki, míg a downloadBase64 kicsit másra volt hivatott. Létrehozunk egy FileReader objektumot, amely a html5-ben érkezett hozzánk, és már elérhető. elérhető használatra. Amely egy ideje képes a blob-ból base64 stringet, pontosabban DataURL stringet készíteni, de ez nem annyira fontos, mivel a DataURL pontosan azt tartalmazza, amire szükségünk van. Bingo, egy kis bonyodalom várt rám, amikor megpróbáltam mindezt a vágólapra helyezni. A szerző a projektben a clipboardjs, könyvtárat használta, amely lehetővé teszi a vágólappal való munkát flash objektumok nélkül, a kiválasztott szöveg alapján. Kezdetben azt terveztem, hogy a base64-et egy display:none; elemből helyezem el, de ebben az esetben nem tudtam a vágólapra tenni, mivel a kiválasztás nem történt meg. Ezért a display:none; helyett azt csináltam, hogy

position: absolute;
z-index: -1;
opacity: 0;

ami lehetővé tette, hogy elrejtsük a szemet elől, de valójában a dokumentumban hagyjuk. Voilà, a feladat teljesítve, a gombom megnyomásakor a vágólapra egy olyan string került:

echo 'base64string' | base64 --decode > config.zip

amit egyszerűen a szerver konzoljába illesztettem, és azonnal megkaptam a zip archívumot az összes konfigurációval.
És természetesen küldtem egy pull requestet a szerzőnek, mivel a projekt aktív és élő, szeretném látni a frissítéseket a szerzőtől és persze a saját gombomat is ) Aki érdekli, itt van az én fork-om a projektről és a pull requestemről, ahol meg lehet nézni, mit javítottam/hozzáadtam.
Mindannyiuknak sikeres fejlesztést! )

Nginx konfigurációk generálása, egy pull request története

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster