Generovanie konfigurácií pre nginx, príbeh jedného pull requestu

Zdravím, priatelia. Na mojich serveroch sa od roku 2006 skvele darí nginx a počas rokov administrácie som nazbieral množstvo konfigurácií a šablón. Veľa som chválil nginx, a tak nejako sa stalo, že som dokonca založil aj hub nginx na habre, chvály
Priatelia ma požiadali, aby som im postavil vývojársku farmu, a namiesto toho, aby som im niesol svoje špecifické šablóny, som si spomenul na zaujímavý projekt nginxconfig.io, ktorý sám rozhadzuje konfigurácie a pripravuje všetko pre lets encrypt. Premýšľal som, prečo nie? Avšak, naštvalo ma, že nginxconfig mi ponúka stiahnuť zip archív v prehliadači, bez toho, aby mi umožnil okamžité stiahnutie na server pomocou wget/fetch/curl. Aký nezmysel, prečo mi to v prehliadači, potrebujem to na servery z konzoly. Rozčúlil som sa, a tak som sa pozrel na github, aby som videl vnútornosti projektu, čo viedlo k jeho forku a následne k pull requestu. O ktorom by som nehovoril, keby nebol zaujímavý 😉

Generovanie konfigurácií pre nginx, príbeh jedného pull requestu

Samozrejme, predtým, ako som začal hrabať v zdrojovom kóde, som sa pozrel, odkiaľ chrome ťahá vygenerovaný zip archív s konfiguráciami, a tam ma čakal adresa začínajúca na „blob:“, wow. Už bolo jasné, že služba v skutočnosti nič negeneruje, že to všetko robí javascript. Skutočne, zip archív generuje samotný klient, prehliadač, javascript. T.j. krása spočíva v tom, že projekt nginxconfig.io môže byť jednoducho uložený ako html stránka, nahraný na nejaký narod.ru a bude fungovať ) Je to veľmi zábavné a zaujímavé riešenie, avšak je to veľmi nepohodlné na nastavovanie serverov, vlastne presne to, na čo bol tento projekt vytvorený. Sťahovať vygenerovaný archív prehliadačom a potom ho prenášať na server pomocou nc... v roku 2019? Stanovil som si úlohu nájsť spôsob, ako stiahnuť získanú konfiguráciu okamžite na server.
Po tom, čo som urobil fork projektu, som začal rozmýšľať, aké mám možnosti. Úloha sa zložila tým, že som nechcel odbočiť od podmienky, že projekt musí zostať čistým front-endom, bez akéhokoľvek back-endu. Samozrejme, najjednoduchšie riešenie by bolo nasadiť nodejs a nutiť ho generovať archív s konfiguráciami cez priame odkazy.
Možností teda nebolo veľa. Presnejšie, napadla mi iba jedna. Musíme nastaviť konfigurácie a získať odkaz, ktorý môžeme skopírovať do konzoly servera, aby sme získali zip archív.
Niekoľko textových súborov vo vytvorenom zip archive malo veľmi malú veľkosť, doslova niekoľko kilobajtov. Zjavné riešenie bolo získať base64 reťazec zo vygenerovaného zip archívu a poslať ho do schránky, zatiaľ čo na serveri sa to vykonalo príkazom v konzole.

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

mohli by sme vytvoriť tento zip súbor.

nginxconfig.io bol napísaný v AngularJS, ani si neviem predstaviť, koľko kilometrov kódu by bolo potrebných, keby autor nevybral reaktívny javascript framework. Ale dobre si predstavujem, ako by mohlo byť všetko oveľa jednoduchšie a krajšie realizované na VueJS, aj keď to je už úplne iná téma.
V súboroch projektu vidíme metódu generovania zip archívu:

$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',
	});
};

všetko je dosť jednoduché, pomocou knižnice jszip sa vytvára zip, do ktorého sa ukladajú konfiguračné súbory. Po vytvorení zip archívu, js ho dodáva prehliadaču pomocou knižnice FileSaver.js:

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

kde content je získaný blob objekt zip archívu.

O.K., všetko, čo som musel urobiť, bolo pridať ďalšie tlačidlo vedľa a pri jeho stlačení neukladať získaný zip archív do prehliadača, ale získať z neho base64 kód. Trochu experimentovaním som získal 2 metódy namiesto jednej downloadZip:

$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,/, '');
			// v premennej base64 je presne potrebný zip archív vo forme base64 reťazca
		}
	});

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

Ako ste si mohli všimnúť, generáciu samotného zip archívu som presunul do súkromnej metódy generateZip, a pretože ide o AngularJS, a sám autor sa riadi spätnými volaniami, nerozhodol som sa implementovať to cez promisy. downloadZip stále na výstupe vykonáva saveAs, zatiaľ čo downloadBase64 robí niečo trochu iné. Vytvárame objekt FileReader, ktorý nám prišiel v HTML5 a už je dosť prístupné pre použitie. Ten, v svojom čase, dokáže z blobu vytvoriť base64 reťazec, presnejšie robí DataURL reťazec, ale nie je to pre nás až tak dôležité, pretože DataURL obsahuje presne to, čo potrebujeme. Bingo, malá nástraha ma čakala pri pokuse umiestniť všetko toto do schránky. Autor v projekte použil knižnicu clipboardjs, ktorá umožňuje pracovať s clipboardom bez flash objektov, na základe vybraného textu. Pôvodne som sa rozhodol umiestniť môj base64 do elementu s display:none;, ale v takom prípade sa mi nepodarilo umiestniť ho do schránky, pretože nedochádzalo k výberu. Preto, namiesto display:none; som urobil

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

, čo mi umožnilo skryť element z očí a vlastne ho nechať na stránke. Voilà, úloha je splnená, po stlačení na moje tlačidlo sa do schránky umiestnila reťazec vo forme:

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

ktorú som jednoducho vložil do konzoly na serveri a okamžite dostal zip archív so všetkými konfiguračnými súbormi.
Samozrejme, odoslal som aj pull request autorovi, pretože projekt je aktívny a živý, chcem vidieť aj aktualizácie od autora a mať svoje tlačidlo ) Kto má záujem, tu je môj fork projektu a samotného pull request, kde si môžete pozrieť, čo som opravil/kolísal.
Všetkým želám úspešný vývoj )

Generovanie konfigurácií pre nginx, príbeh jedného pull requestu

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster