phpFashion

Rubrika Random

Jak zprovoznit https na localhost?

Abych si přiblížil vývoj na lokálním počítači tomu ostrému, zprovoznil jsem si lokální https. Jak na to?

Nejsnazší cesta

V komentářích padla zmínka o aplikaci mkcert, která následující postup udělá za vás. Ale pokud máte rádi ruční práci, čtěte dál :)

Vygenerujeme SSL certifikát

K tomu použijeme program openssl, který určitě na počítači najdete, třeba jako součást Gitu na C:\Program Files\Git\usr\bin\openssl.exe nebo jinde. Následující příkaz vygeneruje klíč do souboru rootCA.key. Bude to po vás chtít vymyslet nějaké heslo, které si uložte.

openssl genrsa -des3 -out rootCA.key 2048

Další příkaz z klíče vygeneruje kořenový SSL certifikát a uloží ho do souboru rootCA.pem. Jeho platnost bude 2000 dní (tedy pět let), ale číslo klidně změňte:

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 2000 -out rootCA.pem

Uvěříme certifikátu

Teď oznámíme operačnímu systému, aby certifikát považoval za důvěryhodný. Postup pro Mac jsem našel třeba tady, pro Windows je pěkně obrázek za obrázkem sepsaný zde a pro české Windows jsem vám jej přeložil:

  • spustit mmc
  • v menu Soubor > Přidat nebo odebrat moduly snap-in
  • doubleclick na Certifikáty v levém okně
  • zvolte Účet počítače a Další
  • ponechte Místní počítač a Dokončit
  • zavřete okno tlačítkem OK
  • v levém okně zvolte Certifikáty, v pravém Důvěryhodné kořenové certifikační autority
  • pravé tlačítko a v kontextovém menu Všechny úkoly > Importovat
  • objeví se Průvodce importem certifikátu, dejte Další
  • vyberte soubor rootCA.pem a odklikejte průvodce na konec

Ufff, jsme v půlce. Pokračujeme v Konzoli:

  • opět v menu Soubor > Přidat nebo odebrat moduly snap-in
  • doubleclick na Editor objektů zásad skupiny
  • stiskněte Dokončit a zavřete okno tlačítkem OK
  • v levém okně otevřete Místní počítač – zásady > Konfigurace počítače > Nastavení systému Windows > Nastavení zabezpečení > Zásady veřejných klíčů
  • doubleclick na Nastavení ověření cesty certifikátů
  • zatrhněte Definovat tato nastavení, Povolit ověřování certifikátů … a Povolit uživatelům důvěřovat certifikátum …
  • potvrďte tlačítkem OK

Hotovo, zavřete Konzoli.

Všichni už certifikátu věří, akorát Firefox chce ještě popostrčit:

  • ve Firefoxu otevřete stránku about:config
  • odklikejte všechna varování
  • vyhledejte položku security.enterprise_roots.enabled
  • doubleklikem změňte hodnotu na true
  • zavřete stránku

Vyrobíme certifikát pro webový server

Klikačku máme za sebou, teď vyrobíme certifikáty pro server. Vytvoříme soubor server.csr.cnf s tímto obsahem:

[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C = CZ
ST = Random
L = Random
O = Random
OU = Random
emailAddress = example@example.com
CN = localhost

A dále soubor v3.ext, kde bude uveden seznam všech domén, které na localhostu provozujete:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
DNS.2 = texy.l
DNS.3 = *.texy.l
DNS.4 = nette.l
DNS.5 = *.nette.l
DNS.6 = navlnachekg.l

Jak vidíte, lokální verze webů provozuji na doménách, které končí na .l, u vás to třeba bude jinak. Ty jednotlivé klíče DNS.1 apod. je potřeba fakt jako idiot postupně očíslovat.

Následujícím krokem vygenerujeme soubory server.key a server.csr:

openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config server.csr.cnf

A konečně vygenerujeme SSL certifikát pro server do server.crt (teď to bude po vás chtít zadat heslo, které jste si vymysleli na začátku):

openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext

Všechny dosud vytvořené soubory včetně hesla si někam uložte. Ať se totiž změní domény, které provozujete lokálně, jen upravíte v3.ext a posledním příkazem znovu vygenerujete certifikát pro server.

Konfigurace webového serveru

Zbývá povolit https na serveru. Tj. nakonfigurovat server tak, aby naslouchal na portu 443, na kterém běží https, a používal vygenerovaný certifikát.

Používám Apache, do jehož konfiguračního soubor httpd.conf jsem přidal následující řádky s cestou k souborům server.key a server.crt:

Listen 443
SSLCertificateFile "C:\Apache24\ssl\server.crt"
SSLCertificateKeyFile "C:\Apache24\ssl\server.key"

Konfiguraci virtuál hostů možná řešíte úplně jinak než já, těžko říct, ale v mém případě zprovoznění obnášelo ke každému virtuálu jako je

<VirtualHost *>
    ServerName localhost
    DocumentRoot "W:/"
</VirtualHost>

doplnit ještě druhý:

<VirtualHost *:443>
    ServerName localhost
    DocumentRoot "W:/"
    SSLEngine on
</VirtualHost>

V nginx by mělo stačit do konfiguračního souboru nginx.conf doplnit pro každý server něco takového:

server {
    listen 443 ssl;
    ssl_certificate     path/to/server.crt;
    ssl_certificate_key   path/to/server.key;
}

A to je vše. Docela mazec, co? Otevřete v prohlížeči https://localhost a jestli se stránka zobrazí, je to důvod k oslavě.


Jak správně nastavit CSP a script-src

Content Security Policy (CSP) je dodatečný bezpečnostní prvek, který prohlížeči říká, jaké další zdroje může stránka načítat a jak může být zobrazena. Chrání tak před vkládáním škodlivého kódu a útokům jako je XSS. Odesílá se v podobě hlavičky sestavené z řady direktiv. Jeho nasazení ale není vůbec triviální.

Obvykle chceme používat JavaScriptové knihovny umístěné na různých místech mimo náš server, například měřící kód Google Analytics, reklamní systémy, captchy atd. A tady bohužel první verze CSP selhává. Vyžaduje přesnou analýzu načítaného obsahu a nastavení správných pravidel. Tedy vytvořit whitelist, výčet všech domén, což není snadné, jelikož některé skripty dynamicky dotahují další skripty z jiných domén, nebo jsou na jiné domény přesměrované atd. A i když si dáte práci a seznam vytvoříte ručně, nikdy nevíte, co se může v budoucnu změnit, takže musíte neustále sledovat, jestli je seznam stále aktuální a opravovat ho. Analýza Google ukázala, že i to pečlivé ladění ve finále vede k tomu, že povolíte tak široký přístup, že celý smysl CSP padá, jen posíláte s každým požadavek mnohem větší hlavičky.

CSP level 2 už k problému přistupuje jinak, pomocí nonce, nicméně teprve třetí verze řešení dotáhla do konce. Bohužel zatím (rok 2019) nemá dostatečnou podporu u prohlížečů.

O tom, jak sestavit direktivy script-src a style-src, aby správně fungovaly i ve starších prohlížečích a přitom s tím bylo co nejméně práce, jsem sepsal podrobný článek v partnerské sekci Nette. V zásadě výsledná podoba může vypadat nějak takto:

script-src 'nonce-XXXXX' 'strict-dynamic' * 'unsafe-inline'
style-src 'nonce-XXXXX' * 'unsafe-inline'

Příklad použití v PHP

Vygenerujeme nonce a odešleme hlavičku:

$nonce = base64_encode(random_bytes(16));

header("Content-Security-Policy: script-src 'nonce-$nonce' 'strict-dynamic' * 'unsafe-inline'");

A vložíme nonce do HTML kódu:

<script nonce="<?=$nonce?>" src="..."></script>

Příklad použití v Nette

Protože Nette má vestavěnou podporu pro CSP a nonce od verze 2.4, stačí v konfiguračním souboru uvést:

http:
	csp:
		script-src: [nonce, strict-dynamic, *, unsafe-inline]
		style-src: [nonce, *, unsafe-inline]

A v šablonách pak používat:

<script n:nonce src="..."></script>
<style n:nonce>...</style>

Monitoring

Než nastavíte nová pravidla pro CSP, vyzkoušejte si je nejprve nanečisto pomocí hlavičky Content-Security-Policy-Report-Only. Ta funguje ve všech prohlížečích podporujících CSP. Při porušení pravidel prohlížeč nezablokuje skript, ale jen pošle notifikaci na URL uvedené v direktivě report-uri. K příjmu notifikací a jejich analýze můžete použít třeba službu Report URI.

http:
	cspReportOnly:
		script-src: [nonce, strict-dynamic, *, unsafe-inline]
		report-uri: https://xxx.report-uri.com/r/d/csp/reportOnly

Můžete zároveň používat obě hlavičky a v Content-Security-Policy mít ověřené a aktivní pravidla a zároveň v Content-Security-Policy-Report-Only si testovat jejich úpravu. Samozřejmě i selhání ostrých pravidlech si můžete nechat monitorovat.

před 6 lety v rubrice Random


Jak souhrnně nazývat třídy a rozhraní?

Názvoslovný oříšek: jak souhrnně označovat třídy a rozhraní? Jak třeba nazvat proměnnou, která může obsahovat jak název třídy, tak rozhraní? Co zvolit místo $class?

Dá se tomu říkat type ($type), nicméně to je zase příliš obecné, protože typem je i řetězec nebo pole. Z pohledu jazyka jím může být i něco komplikovanějšího, třeba ?array. Navíc je sporné, co je v případě objektu jeho typ: je jím název třídy, nebo je to object?

Nicméně souhrnné označení pro třídy a rozhraní skutečně existuje: je jím slovo třída.

Cože?

  1. Z pohledu deklarace je interface hodně ořezaná třída. Může obsahovat jen veřejné abstraktní metody. Což také implikuje nemožnost vytvářet objekty. Rozhraní jsou tedy podmnožinou tříd. A pokud je něco podmnožinou, tak to můžeme označovat názvem nadmnožiny. Člověk je savec, stejně jako rozhraní je třída.
  2. Nicméně je tady ještě pohled užití. Třída může dědit jen od jedné třídy, ale může implementovat vícero rozhraní. Nicméně tohle je omezení týkající se tříd, samotné rozhraní za to nemůže. Obdobně: třída nemůže dědit od final třídy, ale přitom final třídu pořád vnímáme jako třídu. A také pokud třída může implementovat víc rozhraní (tj. tříd, viz 1.), stále je vnímejme jako třídy.

A co traity? Ty sem vůbec nepatří, z hlediska OOP jednoduše neexistují.

Tedy problém se společným pojmenováním tříd a rozhraní je vyřešen. Říkejme jim prostě třídy.

classes + interfaces = classes

No jo, ale vznikl tady problém nový. Jak říkat třídám, které nejsou rozhraní? Tedy jejich doplňku. Tomu, co se ještě na začátku článku nazývalo třídy. Nerozhraní? Nebo implementations? 🙂

To je ještě větší oříšek. To je pořádný ořech. Víte co, raději zapomeňme na to, že rozhraní jsou také třídy, a tvařme se opět, že každý OOP identifikátor je buď třída, nebo rozhraní. Bude to snazší.



Za GitHub krásnější se Stylishem

Stylish je doplněk do Chrome, který umožňuje přidat webovým stránkám vlastní CSS styly.

(Lze ho nainstalovat i do nové Opery, nejprve si přidejte Download Chrome extension a pak už ho přímo nainstalujete z Chrome webstore.)

Stylish jsem si přidal kvůli GitHubu, který mě štve příliš širokými tabulátory a hlavně nezalamováním řádků s textem, bez čehož se podobné commity vůbec nedají číst.

Zalamování jsem vyřešil stylem:

div.blob-wrapper td.blob-code {
  	white-space: pre-wrap !important;
}

A tabulátory:

html * {
	tab-size: 4 !important;
}

Pak jsem si ještě vzpomněl, jak mi vadí nevhodně umístěné tlačítko „Close pull request“ hned vedle „Comment“ a posunul jsem ho trošku bokem:

button.js-comment-and-button {
	float: left !important;
	color: #C22;
}

A hned je svět krásnější 🙂


Jak efektivně píšu na klávesnici

psaní na klávesnici

Naučit se psát všemi deseti, zvládnou správné prstoklady – to je nepochybně prima přednost. Ale mezi námi, sám datluji celý život dvěma prsty a při psaní přikládám daleko větší důraz něčemu jinému. A tím je rozložení klávesnice.

Webmasteři, programátoři nebo copywriteři narážejí na problém, že spousta často používaných znaků na české klávesnici buď úplně chybí, nebo je hůř přístupná. Nejhůř jsou na tom typografické znaky, jako české uvozovky „ “, výpustka …, křížek ×, copyright © atd. Obvykle se to řeší přepínáním mezi dvěma klávesnicemi, českou a anglickou, a osvojením si milionu zkratek Alt-číslo, které chybějící znaky suplují. Ať už tak či onak, jedná se o značné brzdy tvořivosti. Nešlo by to udělat lépe?

Vlastní rozložení klávesnice

Řešením je si vytvořit vlastní rozložení klávesnice. To své jsem si vypiplal asi před deseti lety a je vhodné pro programátory, webdesignery, copywritery, obsahuje všechny důležité typografické vychytávky, jako je pomlčka, dvojité a jednoduché uvozovky atd., intuitivně umístěné. Rozložení si můžete samozřejmě upravit, viz dále.

Všechny typografické znaky jsou dosažitelné přes pravý Alt, nebo-li AltGr. Rozložení je intuitivní:

  • české dvojité uvozovky „“ AltGr-< AltGr->
  • české jednoduché uvozovky ‚‘ AltGr-Shift-< AltGr-Shift->
  • nedělitelná mezera AltGr-mezerník
  • křížek × AltGr-X
  • trojtečka … AltGr-D (dot)
  • pomlčka – AltGr-spojovník
  • dlouhá pomlčka — AltGr-Shift-spojovník
  • copyright © AltGr-C
  • trademark ™ AltGr-T
  • AltGr-E
  • ø AltGr-O

A tak dále, na celé rozložení se můžete podívat na obrázcích.

Ke stažení: klávesnice dg v5 (pro Windows)

Jak se tvoří vlastní rozložení klávesnice?

Je to snadné a je to zábavné. Přímo od Microsoftu si stáhněte kouzelný a dobře utajený program Microsoft Keyboard Layout Creator (ke svému chodu vyžaduje .NET Framework).

Hned při spuštění se Vám zobrazí „prázdná“ klávesnice, tedy taková, kde ještě není definováno žádné rozložení kláves. Začínat na zelené louce není to pravé ořechové, proto si najděte v menu příkaz Load existing keyboard a načtěte některé standardní rozložení (například klasickou českou klávesnici).

Microsoft Keyboard Layout Creator

U každé klávesy můžete definovat znak, který se napíše při samostatném stisku a dále při použití přepínačů (tedy Shift, Ctrl+Alt (pravý Alt), pravý Alt +Shift, Caps Lock a Shift+Caps Lock). Dále lze klávesu označit jako mrtvou (dead key), což znamená, že znak se napíše až po stisknutí další klávesy. Takto funguje například háček a čárka v české klávesnici.

Skutečná bomba je export hotové klávesnice. Výsledkem je plnohodnotný ovladač klávesnice včetně instalačního programu. Takže svou klávesnici si můžete pověsit na internet a nainstalovat na jiné počítače.


Jak na GitHub a pull request z příkazové řádky

Tuhle jsem zveřejnil skript na cherry-pickování přímo z GitHubu, který dodnes používám, ale bylo otravné tím stahovat celé pull requesty, pokud obsahovaly víc komitů. Takže jsem ho naučil stahovat je na jeden zátah. Opět stačí jako argument uvést URL:

pullpick.php https://github.com/nette/tracy/pull/58

Oproti cherry-picku je potřeba navíc zjistit zdrojový repozitář a větev, k čemuž použijeme GitHub API. Skript vypadá takto:

<?php
$url = @$_SERVER['argv'][1];

if (!preg_match('#github.com/(<a href="#fn" class="footnote">[/]</a>+)/(<a href="#fn" class="footnote">[/]</a>+)/pull/(\w+)#', $url, $m)) {
	die('Invalid URL');
}

list(, $name, $repo, $pull) = $m;

$context = stream_context_create(array('http' => array('user_agent' => 'Me')));
$info = file_get_contents("https://api.github.com/repos/$name/$repo/pulls/$pull", false, $context);
$info = json_decode($info);
if (!isset($info->head->repo->clone_url, $info->head->ref)) {
	die('Missing repo info.');
}
passthru("git checkout -b pull-$pull master");
passthru("git pull --no-tags {$info->head->repo->clone_url} {$info->head->ref}");

Pull request se stáhne do nové větve s názvem jako pull-123.

Mám i skript na vytvoření nového pull requestu. Spustíte jej ve větvi, ze které chcete PR vytvořit, bez parametrů. On větev pushne do vašeho forku a poté otevře prohlížeč s formulářem pro vytvoření pull requestu:

<?php
$remote = 'dg'; // tady dejte název 'remote' vedoucí k forku na GitHubu

exec('git remote -v', $remotes);

$repo = null;
foreach ($remotes as $rem) {
	if (preg_match('#^' . preg_quote($remote) . '\tgit@github.com:(.+)\.git \(#', $rem, $m)) {
		$repo = $m[1];
		break;
	}
}

if (!$repo) {
	die('Not Github repo');
}

exec('git rev-parse --abbrev-ref HEAD', $branch);
$branch = $branch[0];
if (!$branch) {
	die('Unable to retrieve branch name');
}

echo "Pushing to $repo & $branch\n";
exec("git push --set-upstream $remote $branch");

$url = "https://github.com/$repo/compare/$branch?expand=1";
exec('start "" ' . $url); // tohle otevře prohlížeč pod Windows. Pro jiné OS si upravte.

Jak komitovat se záruční smlouvou?

Už jsem odpověděl na spoustu pull requestů „Can you add tests?“ Ale ne proto, že bych byl testofil, nebo abych dotyčného buze prudil.

Pokud posíláte pull request, který opravuje nějakou chybu, tak pochopitelně musíte před odesláním vyzkoušet, jestli skutečně funguje. Kolikrát si člověk myslí, že něco snadno fixne a ejhle, rozbije to ještě víc. Nechci se opakovat, ale tím, že to vyzkoušíte, jste vyrobili test, tak ho jen přiložte.

(Bohužel někteří lidé svůj kód doopravdy nevyzkouší. Kdyby to šlo, dával bych měsíční bany za pull requesty vytvořené přímo ve webovém editoru Githubu.)

Ale to stále není ten nejhlavnější důvod: Test je jediná záruka, že vaše oprava bude fungovat v budoucnu.

Už mnohokrát se stalo, že někdo poslal pull request, který mi nebyl užitečný, ale upravoval funkcionalitu důležitou pro něj. Zejména pokud to byl někdo, koho znám, a vím, že je dobrý programátor, tak jsem to mergnul. Pochopil jsem, k čemu to chce, nevadilo to ničemu jinému, tak jsem PR přijal a v tu chvíli vypustil z hlavy.

Pokud svůj pull request doplnil testem, tak jeho kód dodnes funguje a bude fungovat i nadále.

Pokud ho testem nedoplnil, tak se klidně může stát, že mu to nějaká další úprava rozbije. Ne schválně, prostě se to stane. Nebo už se to stalo. A nemá smysl láteřit, jaký jsem vůl, že jsem mu už potřetí rozbil jeho kód, ačkoliv jsem před 3 lety přijal jeho pull request, si to snad musím pamatovat né, takže mu to snad dělám naschvál… Nedělám. Nikdo si nepamatujeme, co jsme měli před třemi lety na svačinu.

Pokud vám na nějaké funkcionalitě záleží, přiložte k ní test. Pokud vám na ni nezáleží, vůbec ji neposílejte.

před 11 lety v rubrice Random


Proč přejmenovat Program Files a kde končí sranda?

Vždycky jsem obdivoval Microsoft, jak dokáže perfektně pojmenovávat systémové adresáře, třeba takové c:\Documents and Settings namísto trapného /home nebo /Users, nicméně vždycky mě trápila složka Program Files, protože na jedné straně je skvělé, že v názvu uvádí, že uvnitř jsou soubory (což třeba mekaře u takové /Applications vůbec nemusí napadnout), na druhou stranu úplně opomíjí adresáře.

Navrhuji proto každou složku, která může obsahovat soubory nebo adresáře, tedy každou složku, doplnit v názvu touto informací. Tedy v příštích Windows přejmenovat c:\Program Files na přesnější c:\Program Files and Directories.

To by mohlo zase více posunout Microsoft tam, kde v poslední době je.

před 11 lety v rubrice Random


Nevěřím statistikám, které si sám nezfalšuji

Václav Novotný připravil infografiku porovnávající aktivitu vývojářů v Nette a Symfony. Rád a zvědavě se podívám, leč bez vysvětlení metriky umí být čísla krutě zrádná. S nadsázkou: při určitém workflow a naivním měření mohu ve statistikách vyjít jako autor 100 % kódu, aniž bych naprogramoval jedinou řádku.

I při přímočarých workflow je poměřování množství komitů zákeřné. Není komit jako komit. Pokud přidáte pětici důležitých komitů a zároveň deset lidí vám opraví překlepy v komentářích, jste co do počtu komitů autorem třetiny kódu. Což ale není pravda, jste autorem celého kódu, opravy překlepů se za autorství (jak ho obvykle vnímáme) nepovažují.

V GITu dále věc komplikují „merge-commits“. Pokud někdo připraví zajímavý komit a vy ho schválíte (tedy vznikne ještě merge-commit), jste autorem poloviny komitů. Ale jaký je vlastně skutečný podíl? Obvykle nulový, schválení je otázka jednoho kliknutí v GitHubu, byť někdy diskusí strávíte víc času, než kdybyste si kód napsal sám, ale neuděláte to, protože potřebujete vývojáře vychovávat.

Proto místo počtu komitů je vhodnější analyzovat jejich obsah. Nejjednodušší je brát v úvahu počet změněných řádek. Ale i to může být zavádějící: pokud vytvoříte 100 řádkovou třídu a někdo jiný soubor s ní jen přejmenuje (či rozdělí na dva), „změnil“ vlastně 200 řádků a opět jste autorem třetiny.

Pokud týden ladíte u sebe několik komitů a až potom je pošlete do repozitáře, jste v počtu změněných řádek v nevýhodě oproti tomu, kdo je pošle hned a teprve poté dolaďuje následujícími komity. Nebylo by tedy od věci analyzovat třeba až souhrny za celý den. Je třeba odfiltrovat i údržbové komity, zejména ty, které mění u všech souborů letopočet nebo verzi v hlavičce.

Do toho přicházejí ještě situace, kdy se automatizovaně kopírují komity z jedné větve do jiné, nebo do jiného repozitáře. Což de facto znemožňuje dělat jakékoliv globální statistiky.

Analýza jednoho projektu je věda, natož ta srovnávací. Docela mi to připomíná skvělý analytický kvíz od Honzy Tichého.


Související: Jak se počítá „Hall of fame“ na nette.org


phpFashion © 2004, 2025 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.