6 min read
Na den hackerem

Všechna moje rána většinou začínají typickou kávou a sledováním na všech zprávách, co se tak různě děje ve světě. Dneska mě zaujal příspěvek od jednoho pána, který se na facebooku pochlubil tím, že si naprogramoval nějakou hříčku pro ostatní v umělé inteligenci. Neváhal jsem a hned na to kliknul.

Jednalo se o relativně jednoduchou appku, která prostě jen počítá kolik za 10 sekund zvládnete udělat kliků, ty kliky pak nějak uloží k sobě do databáze a ukáže se tabulka s nejlepšími desíti.

obr

Nic míň, nic víc. Zkusil jsem překonat těch top 10 a samozřejmě se mi to nepodařilo, tak jsem prostě zavřel tuhle appku a šel dál se svým životem.

Fakt?

No tak jo, tak dobře, nešel dál se svým životem a ihned otevřel F12, abych se podíval, co tam je za kód.

Tenhle konkrétní případ mě zajímal, protože se v podstatě jednalo o člověka, který nikdy ve svém životě neprogramoval a nyní si do ruky vzal Cursor s nějakým AI agentem a šel na věc. Hned mi to připomnělo jedno meme tehdá z Redditu, kdy se týpek snažil vytvořit startup s AI vygenerovanou SaaS webovkou a prodal dokonce i pár služeb lidem, než mu to zjistili lidi a kleknuli mu webovku celou.

meme

zdroj: reddit.com/ProgrammerHumor

Upřímně, doufal jsem, že to nebude jeden z těch případů. Že tam najdu nádherně vytvořený kód, který respektuje security best practices a že bude mít solidně rozdělený frontend s backendem, ať už přes Flask, nebo cokoliv jinýho jako třeba React. Že najdu komentáře, jak co která komponenta dělá pro svoje sebvzdělávání. Že…

...
<script type="module">
  import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js";
  import { getFirestore, collection, addDoc, query, orderBy, limit, onSnapshot, serverTimestamp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore.js";

  // Konfigurace tvého Firebase
  // (Abych nebyl zlej, tak pro účely téhle webovky anonymizováno)
  const firebaseConfig = {
    apiKey: "xxx",
    authDomain: "xxx",
    projectId: "xxx",
    storageBucket: "xx",
    messagingSenderId: "xxx",
    appId: "xxx"
  };

  const app = initializeApp(firebaseConfig);
  const db = getFirestore(app);
  const scoresRef = collection(db, "scores");
  ...

Chjo.

Tohle je přesně ten důvod, proč neposlouchat slepě umělé inteligenci a raději si ověřovat co která věc dělá, ideálně i s nějakým dalším kamarádem programátorem.

Ale protože jsem člověk, co je občas příliš zvědavý namísto toho, abych správně dělal svoji práci, tak mě zajímalo co všechno s tím můžu dělat. Napadlo mě, že Firebase bude nějaká databáze, takže bych správně mohl provádět všechny základní databázové úkony (DELETE, UPDATE, INSERT…)

No a protože by se mi strašně líbilo mít své jméno na první příčce toho žebříčku…

Cesta za prvním místem

Protože jsem doteď neměl s Firebase žádné zkušenosti, začal jsem googlit, jak vůbec s tou databází pracovat z Pythonu. Všude se psalo o Firebase Admin SDK a nějakém speciálním .json souboru s credentials, který je potřeba stáhnout z Firebase Console a uložit na server. Neměl jsem čas to studovat nějak víc do hloubky, takže jsem zkoušel všechny možnosti a pokračovat s tou, která mi dá ten kýžený efekt.

Ale pak mě napadlo zkusit to nejjednodušší – co když prostě pošlu POST request na Firebase REST API? Vzal jsem tu konfiguraci, co byla přímo v HTML souboru (apiKey, projectId…), sestavil URL a zkusil přidat záznam.

Base URL jsem někde vyhrabal z internetu a postupně zkoušel všechny IDčka co byly v configu a zkusil klasický cURL.

StatusCode        : 200
StatusDescription : OK
Content           : {
                      "documents": [
                        {
                          "name": "projects/xxx/databases/(default)/documents/scores/0L1yBlkdD5AoV97aPz1H",
                          "fields": {
                            "createdAt": {
                              "timestampValue": "2...
RawContent        : HTTP/1.1 200 OK
                    X-Debug-Tracking-ID: 13627572476665769434;o=1
                    Vary: X-Origin,Referer,Origin,Accept-Encoding
                    X-XSS-Protection: 0
                    X-Frame-Options: SAMEORIGIN
                    X-Content-Type-Options: nosniff
                    Alt-Sv...
Forms             : {}
Headers           : {[X-Debug-Tracking-ID, 13627572476665769434;o=1], [Vary, X-Origin,Referer,Origin,Accept-Encoding], [X-XSS-Protection, 0]
                    , [X-Frame-Options, SAMEORIGIN]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 26286

200 OK? Lmao.

Chtělo to ještě jeden request, abych věděl to databázový schéma…

{
"name": "projects/xxx/databases/(default)/documents/xxx",
"fields": {
  "clicks": {
    "integerValue": "0"
  },
  "name": {
    "stringValue": "Jaroslav rac"
  },
  "createdAt": {
    "timestampValue": "2026-01-20T17:47:27.716Z"
  }
},
"createTime": "2026-01-20T17:47:27.755850Z",
"updateTime": "2026-01-20T17:47:27.755850Z"
},

Bingo. Měl jsem tedy všechno na to, abych byl první. Vzhledem k tomu, že jsem používal klasický REST API, tak jsem něco podobného napsal i v Pythonu:

import requests

FIREBASE_CONFIG = {
    "apiKey": "xxx",
    "authDomain": "xxx",
    "projectId": "xxx",
    "storageBucket": "xxx",
    "messagingSenderId": "xxx",
    "appId": "xxx"
}

BASE_URL = f"https://firestore.googleapis.com/v1/projects/{FIREBASE_CONFIG["projectId"]}/databases/(default)/documents"

def add_score(name, clicks):
    url = f"{BASE_URL}/scores"
    
    data = {
        "fields": {
            "name": {"stringValue": name},
            "clicks": {"integerValue": clicks},
            "createdAt": {"timestampValue": datetime.utcnow().isoformat() + "Z"}
        }
    }
    
    response = requests.post(url, json=data)
    
    if response.status_code in [200, 201]:
        print(f"Score added: {name} - {clicks} clicks")
        return True
    
    print(f"Error adding score: {response.status_code}")
    print(response.text)
    return False

No a z toho vzešlo…

hacked!

Musel jsem se popadnout za hlavu. To ID, které Firebase potřebovalo, bylo jen projectId, ne API klíč, jak jsem si původně myslel. A hlavně to nechtělo žádnou autentizaci.

Samozřejmě jsem to zkusil rozšířit o nějakou další funkcionalitu, takže i DELETE se mi tam povedlo přidat, UPDATE a klasické operace s tou databází přes REST. Po chvíli blbnutí jsem toho nechal a radši toho týpka informoval, že má blbě napsanej kód.

🎉

Tak… myslím si, že ještě nějakou dobu budu mít práci jako programátor. Jestli takových webovek bude čím dál tím víc, tak velké obavy o svou práci nemám.

Vibecoding vždycky zněl jako strašně dobrý nápad pro nováčky, ale realita je jiná. Protože nováčci vlastně nic neví a neznají ekosystém ani kontext kolem programování, stávají se přesně tyhle věci. Vibecoding může být skvělá zbraň v rukou mediora nebo seniora, který si tím urychlí práci — ale v rukou zelenáče? Katastrofa. Do skutečně autonomní AI máme ještě hodně daleko.

Pokud se jedná o jednoduchou webovku bez databáze s nějakým základním CSS a JS, možná to není špatný tool. Problém je ale v tom, že tím člověk přichází o schopnost přemýšlet nad svým codebase, rozumět mu a postupně ho vylepšovat. Moc si například nedokážu představit truhláře, kterému IKEA vyrobí stůl a on ho má nějak udržovat a vylepšovat. Základy jsou vždy lepší, když si je člověk naučí udělat sám — naučí se je implementovat a v případě chyb umět bug opravit. Má tak bližší vztah ke kódu a začne si vážit, kolik toho inženýrství v tom IT vlastně je.

A víš co? Těch problémů s jeho webovkou je víc. Třeba tam používá innerHTML, díky kterému bychom mu tam mohli nadělat pěknou paseku…

A nakonec… Jsem první! Hehe. 🔥