// ── fiko_lisans — lisans üretici CLI (YALNIZ ÜRETİCİ MAKİNEDE) ────────────── // Bu araç MÜŞTERİYE DAĞITILMAZ. Özel anahtar yalnız burada kullanılır; fikocad.exe // içinde yalnız AÇIK anahtar gömülüdür (lisans_yukle.cpp). // // fiko_lisans anahtar // Yeni ECDSA P-256 çifti üretir. Özel anahtarı GÜVENLİ sakla (kaybolursa // eski lisanslar doğrulanamaz; sızarsa herkes lisans üretir). // fiko_lisans imzala [cikti.fkl] [--duz] // Gövdeyi imzalar, "imza=" satırını ekleyip .fkl yazar (varsayılan: lisans.fkl). // Çıktı VARSAYILAN OLARAK ŞİFRELİDİR (müşteri içeriği okuyamasın); --duz ile // eski düz metin biçimi yazılır (hata ayıklama). // fiko_lisans dogrula // İmzayı doğrular ve içeriği okunur biçimde yazar (kesilen lisansı teslimden // önce kontrol etmek için). // fiko_lisans politika-imzala [cikti.txt] // UZAK POLİTİKA (kill-switch) gövdesini imzalar → sunucuya koyacağın dosya. // Düz metin yazar (zarf YOK — politika herkese açık; güven imzadan gelir). // fiko_lisans politika-dogrula // Uzak politika dosyasını doğrular + kararları özetler (yüklemeden önce test). // fiko_lisans canli-imzala <0|1> [cikti.json] // CANLI KANAL kararı imzalar (anında engelle/izin — WS sunucusuna POST edilecek // tek satırlık JSON üretir). 0=izinli/kilit aç, 1=engelli/kilitle. Özel anahtar // YALNIZ burada kullanılır; sunucu bu JSON'u sadece BAĞLI istemciye İLETİR, // kendisi imzalamaz/doğrulamaz — imza doğrulaması istemcide (gömülü açık anahtar). #include #include #include #include #include #include #include "fiko/cekirdek/kripto.hpp" #include "fiko/cekirdek/lisans_dosya.hpp" #include "fiko/cekirdek/lisans_uzak.hpp" #include "fiko/cekirdek/makine_kimlik.hpp" using namespace fiko; namespace { std::string dosyaOku(const char* yol) { std::ifstream f(yol, std::ios::binary); if (!f) return ""; std::ostringstream ss; ss << f.rdbuf(); return ss.str(); } // JSON dizge değeri için kaçış (mesaj alanı tırnak/ters boşlu/satır sonu içerebilir). std::string jsonKacisla(const std::string& s) { std::string o; o.reserve(s.size()); for (char c : s) { if (c == '"' || c == '\\') { o += '\\'; o += c; } else if (c == '\n') o += "\\n"; else if (c == '\r') { /* atla */ } else if ((unsigned char)c < 0x20) o += ' '; else o += c; } return o; } int kullanim() { std::puts("Kullanim:"); std::puts(" fiko_lisans anahtar [ozel.key] (ozel anahtar dosyaya, acik ekrana)"); std::puts(" fiko_lisans imzala [cikti.fkl] [--duz]"); std::puts(" cikti VARSAYILAN SIFRELI; --duz = eski duz metin (hata ayiklama)"); std::puts(" fiko_lisans dogrula (sifreli/duz farketmez)"); std::puts(" fiko_lisans yapi (dagittigin ikilinin hash'i)"); std::puts(" fiko_lisans parmakizi (BU makinenin makine= satirlari)"); std::puts(" fiko_lisans politika-imzala [cikti.txt]"); std::puts(" Uzak politika (kill-switch): engelle/izin listesi → sunucuya koy"); std::puts(" fiko_lisans politika-dogrula "); std::puts(" fiko_lisans canli-imzala <0|1> [cikti.json]"); std::puts(" Canli kanal karari: 0=izinli/ac 1=engelli/kilitle. WS sunucusuna POST icin."); std::puts(""); std::puts("Politika govdesi ornegi (imza satiri EKLEME):"); std::puts(" # FikoCAD Uzak Politika v1"); std::puts(" surum=1 (her degisiklikte ARTTIR — geri sarma korumasi)"); std::puts(" zaman=1756100000 (unix saniye)"); std::puts(" mod=engelli (engelli=kara liste | izin=beyaz liste)"); std::puts(" engelle=FKC-2026-0001 (seri no — mod=engelli iken anlamli)"); std::puts(" izin=FKC-2026-0010 (seri no — mod=izin iken anlamli)"); std::puts(" mesaj=Odeme gecikmesi (engellenen kullaniciya gosterilecek ileti, ops.)"); std::puts(""); std::puts("Govde ornegi (imza satiri EKLEME, arac ekler):"); std::puts(" # FikoCAD Lisans v1"); std::puts(" musteri=Akcali Dokum"); std::puts(" seri=FKC-2026-0001"); std::puts(" urun=fikocad"); std::puts(" kisitli=1"); std::puts(" komut=geometri.kutu (tek tek satis)"); std::puts(" komut=cam.* (modul jokeri)"); std::puts(" kota=cam.gkod:100 (komut basina kullanim limiti)"); std::puts(" bitis=2000000000 (unix saniye; 0/yok = suresiz)"); std::puts(" makine= (musterinin panodan gonderdigi satirlar)"); std::puts(" makineTolerans=3"); std::puts(" yapi= (opsiyonel: lisansi O ikiliye kilitler)"); std::puts(""); std::puts("PAKET blogu (paket= satirindan sonraki komut/kota/bitis O pakete aittir):"); std::puts(" paket=cam"); std::puts(" paket.ad=CAM 3 Aylik"); std::puts(" paket.bitis=1900000000 (paketin KENDI bitisi; 0/yok = lisans bitisi)"); std::puts(" komut=cam.*"); std::puts(" kota=cam.gkod:100/ay (donem: gun|hafta|ay|yil; yoksa omur boyu)"); std::puts(" kota=cam.simulasyon:5/gun"); std::puts(""); std::puts("Ayni lisansta birden cok paket olabilir; her biri ayri bitis/kota tasir."); std::puts("Donem sayaclari takvim penceresi degisince sifirlanir (paket bitisini asamaz)."); return 2; } } // namespace int main(int argc, char** argv) { if (argc < 2) return kullanim(); const std::string komut = argv[1]; if (komut == "anahtar") { std::string ozel, acik; if (!kripto::p256AnahtarUret(ozel, acik)) { std::puts("HATA: anahtar uretilemedi"); return 1; } // Ozel anahtar EKRANA BASILMAZ: terminal gecmisi, ekran goruntusu, CI log'u ve // omuz-ustu okuma hepsi sizinti yoludur. Dosyaya yazilir; yol bildirilir. const char* ozelYol = argc > 2 ? argv[2] : "lisans_ozel.key"; std::ofstream f(ozelYol, std::ios::binary); if (!f) { std::printf("HATA: ozel anahtar yazilamadi: %s\n", ozelYol); return 1; } f << ozel << '\n'; f.close(); std::printf("Ozel anahtar yazildi : %s\n", ozelYol); std::puts(" -> YEDEKLE ve GIZLE. Kaybolursa kestigin lisanslar dogrulanamaz;"); std::puts(" sizarsa herkes lisans uretir. Depoya (git) KOYMA."); std::printf("Acik anahtar (fikocad'a gom):\n%s\n", acik.c_str()); return 0; } if (komut == "parmakizi") { const MakineParmakIzi& p = makineParmakIzi(); if (p.alanSayisi() == 0) { std::puts("HATA: hicbir donanim alani okunamadi (node-lock kurulamaz)"); return 1; } for (const std::string& h : p.hashListesi()) std::printf("makine=%s\n", h.c_str()); std::printf("makineTolerans=%d\n", p.alanSayisi() >= 4 ? 3 : p.alanSayisi()); return 0; } if (komut == "yapi") { if (argc < 3) return kullanim(); u8 d[32]; if (!kripto::sha256Dosya(argv[2], d)) { std::printf("HATA: okunamadi: %s\n", argv[2]); return 1; } std::printf("yapi=%s\n", kripto::baytHex(d, 32).substr(0, 32).c_str()); return 0; } if (komut == "imzala") { if (argc < 4) return kullanim(); const std::string govde = dosyaOku(argv[2]); if (govde.empty()) { std::printf("HATA: govde okunamadi: %s\n", argv[2]); return 1; } // 3. arguman hex DEGIL bir dosya yolu olabilir (ozel anahtari komut satirina // yapistirmak zorunda kalma: terminal gecmisine duser). std::string ozelHex = argv[3]; if (ozelHex.size() != 192) { const std::string dosyadan = dosyaOku(argv[3]); if (!dosyadan.empty()) { ozelHex.clear(); for (char c : dosyadan) if (std::isxdigit((unsigned char)c)) ozelHex.push_back(c); } } // Ham metni DEĞİL kanonik gövdeyi imzala — doğrulayan uygulama da onu görür // (BOM/CRLF/fazladan boşluk/yorum satırı imzayı bozmaz). const std::string kanonik = lisansKanonikGovde(govde); std::string imza; if (!kripto::imzala(kanonik, ozelHex, imza)) { std::puts("HATA: imzalanamadi (ozel anahtar 192 hane olmali)"); return 1; } // Bayrak nerede olursa olsun ayikla; cikti = kalan ilk serbest arguman. bool duz = false; const char* cikti = "lisans.fkl"; for (int i = 4; i < argc; ++i) { if (std::string(argv[i]) == "--duz") duz = true; else cikti = argv[i]; } std::string tam = govde; if (!tam.empty() && tam.back() != '\n') tam += '\n'; tam += "imza=" + imza + "\n"; // VARSAYILAN ŞİFRELİ: musteri .fkl'i Notepad'de acip komut/kota/makine listesini // okumasin. Imza zaten icerideki duz metnin uzerinde — zarf yalniz gizlilik. if (!duz) { u8 anahtar[32]; lisansZarfAnahtari(anahtar); const std::string zarf = lisansZarfla(tam, anahtar); if (zarf.empty()) { std::puts("HATA: lisans sifrelenemedi (--duz ile duz metin yazabilirsin)"); return 1; } tam = zarf; } std::ofstream f(cikti, std::ios::binary); if (!f) { std::printf("HATA: yazilamadi: %s\n", cikti); return 1; } f << tam; std::printf("Yazildi: %s (%s)\n", cikti, duz ? "duz metin" : "sifreli"); return 0; } if (komut == "dogrula") { if (argc < 4) return kullanim(); LisansBilgi l; std::string hata; // Sifreli dosya otomatik acilir; duz metin ise zarfCoz aynen geri verir. u8 anahtar[32]; lisansZarfAnahtari(anahtar); const LisansDurum d = lisansCoz(lisansZarfCoz(dosyaOku(argv[2]), anahtar), argv[3], l, hata); std::printf("Durum: %s%s%s\n", lisansDurumMetni(d), hata.empty() ? "" : " — ", hata.c_str()); if (d != LisansDurum::Gecerli) return 1; std::printf("Musteri : %s\n", l.musteri.c_str()); std::printf("Seri : %s\n", l.seri.c_str()); std::printf("Urun : %s (seviye: %s)\n", l.urun.c_str(), l.seviye.c_str()); std::printf("Kip : %s\n", l.kisitli ? "Kisitli" : "Serbest"); std::printf("Bitis : %lld\n", (long long)l.bitis); std::printf("Komut : %d hak\n", (int)l.komutlar.size()); for (const std::string& k : l.komutlar) std::printf(" - %s\n", k.c_str()); std::printf("Makine : %d hash (tolerans %d)\n", (int)l.makineHashleri.size(), l.makineTolerans); for (const auto& k : l.kotalar) std::printf("Kota : %s = %llu / %s\n", k.kimlik.c_str(), (unsigned long long)k.limit, kotaPeriyotMetni(k.periyot).c_str()); for (const LisansPaket& p : l.paketler) { std::printf("Paket : %s (bitis %lld, %d komut, %d kota)\n", (p.ad.empty() ? p.kimlik : p.ad).c_str(), (long long)p.bitis, (int)p.komutlar.size(), (int)p.kotalar.size()); for (const std::string& kk : p.komutlar) std::printf(" komut - %s\n", kk.c_str()); for (const auto& k : p.kotalar) std::printf(" kota - %s = %llu / %s\n", k.kimlik.c_str(), (unsigned long long)k.limit, kotaPeriyotMetni(k.periyot).c_str()); } return 0; } // ── UZAK POLİTİKA (kill-switch) ───────────────────────────────────────────── if (komut == "politika-imzala") { if (argc < 4) return kullanim(); const std::string govde = dosyaOku(argv[2]); if (govde.empty()) { std::printf("HATA: govde okunamadi: %s\n", argv[2]); return 1; } std::string ozelHex = argv[3]; if (ozelHex.size() != 192) { const std::string dosyadan = dosyaOku(argv[3]); if (!dosyadan.empty()) { ozelHex.clear(); for (char c : dosyadan) if (std::isxdigit((unsigned char)c)) ozelHex.push_back(c); } } // Lisansla AYNI kanonikleştirme → BOM/CRLF/yorum farkları imzayı bozmaz. const std::string kanonik = lisansKanonikGovde(govde); std::string imza; if (!kripto::imzala(kanonik, ozelHex, imza)) { std::puts("HATA: imzalanamadi (ozel anahtar 192 hane olmali)"); return 1; } const char* cikti = argc > 4 ? argv[4] : "uzak_politika.txt"; std::string tam = govde; if (!tam.empty() && tam.back() != '\n') tam += '\n'; tam += "imza=" + imza + "\n"; std::ofstream f(cikti, std::ios::binary); if (!f) { std::printf("HATA: yazilamadi: %s\n", cikti); return 1; } f << tam; std::printf("Yazildi: %s\n", cikti); std::puts(" -> Bu dosyayi sunucuya koy; istemcide 'lisans_uzak_url' ayarina adresini yaz."); return 0; } if (komut == "politika-dogrula") { if (argc < 4) return kullanim(); UzakPolitika p; std::string hata; const UzakPolitikaDurum d = uzakPolitikaCoz(dosyaOku(argv[2]), argv[3], p, hata); std::printf("Durum: %s%s%s\n", uzakPolitikaDurumMetni(d), hata.empty() ? "" : " — ", hata.c_str()); if (d != UzakPolitikaDurum::Gecerli) return 1; std::printf("Surum : %llu\n", (unsigned long long)p.surum); std::printf("Zaman : %lld\n", (long long)p.zaman); std::printf("Mod : %s\n", p.mod == UzakMod::EngelliListesi ? "engelli listesi" : "izin listesi"); for (const std::string& s : p.engelliler) std::printf("Engelli: %s\n", s.c_str()); for (const std::string& s : p.izinliler) std::printf("Izinli : %s\n", s.c_str()); if (!p.mesaj.empty()) std::printf("Mesaj : %s\n", p.mesaj.c_str()); // Örnek kararlar (test): listedeki seriler için beklenen sonucu göster. if (!p.engelliler.empty()) std::printf("Ornek karar (%s): %s\n", p.engelliler.front().c_str(), uzakKararMetni(uzakPolitikaKarar(&p, p.engelliler.front()))); return 0; } // ── CANLI KANAL kararı (WebSocket sunucusuna POST edilecek) ──────────────────── if (komut == "canli-imzala") { if (argc < 6) return kullanim(); const std::string seri = argv[2]; const bool engelli = std::string(argv[3]) != "0"; const std::string mesaj = argv[4]; std::string ozelHex = argv[5]; if (ozelHex.size() != 192) { const std::string dosyadan = dosyaOku(argv[5]); if (!dosyadan.empty()) { ozelHex.clear(); for (char c : dosyadan) if (std::isxdigit((unsigned char)c)) ozelHex.push_back(c); } } CanliKarar k; k.seri = seri; k.mesaj = mesaj; k.engelli = engelli; k.zaman = (i64)std::time(nullptr); const std::string kanonik = canliKararKanonik(k); std::string imza; if (!kripto::imzala(kanonik, ozelHex, imza)) { std::puts("HATA: imzalanamadi (ozel anahtar 192 hane olmali)"); return 1; } std::string json = "{\"tip\":\"karar\",\"seri\":\"" + jsonKacisla(seri) + "\",\"engelli\":" + (engelli ? "true" : "false") + ",\"mesaj\":\"" + jsonKacisla(mesaj) + "\",\"zaman\":" + std::to_string(k.zaman) + ",\"imza\":\"" + imza + "\"}"; if (argc > 6) { std::ofstream f(argv[6], std::ios::binary); if (!f) { std::printf("HATA: yazilamadi: %s\n", argv[6]); return 1; } f << json; std::printf("Yazildi: %s\n", argv[6]); } else { std::puts(json.c_str()); } std::fputs( " -> Bu JSON'u sunucunun /admin/karar adresine POST et (Authorization: Bearer " ").\n", stderr); return 0; } return kullanim(); }