refactor: rename project from dgray.io to kashilo.com

This commit is contained in:
2026-02-10 18:43:49 +01:00
parent 4e77ce92f3
commit 9069404942
60 changed files with 260 additions and 260 deletions

View File

@@ -4,7 +4,7 @@ Dieses Dokument hilft AI-Assistenten (Amp, Copilot, etc.) das Projekt zu versteh
## Projekt-Überblick
**dgray.io** ist eine Kleinanzeigen-PWA mit Monero-Bezahlung.
**kashilo.com** ist eine Kleinanzeigen-PWA mit Monero-Bezahlung.
- **Status**: Active Development (Frontend + Directus Backend)
- **Ziel**: Anonyme, dezentrale Marktplatz-Alternative
@@ -17,10 +17,10 @@ Dieses Dokument hilft AI-Assistenten (Amp, Copilot, etc.) das Projekt zu versteh
| Routing | Hash-basierter Client-Side Router (`js/router.js`) |
| i18n | Custom System (`js/i18n.js`), JSON-Dateien in `/locales/` |
| Theming | CSS Variables, Dark/Light Mode |
| Backend | Directus (`api.dgray.io`) |
| Backend | Directus (`api.kashilo.com`) |
| Auth | UUID-basiert, anonym (`js/services/auth.js`) |
| E2E Crypto | TweetNaCl (self-hosted in `js/vendor/`), `box.before` + `secretbox` |
| PoW Captcha | PHP-Server (`pow.dgray.io`), Fallback auf lokal |
| PoW Captcha | PHP-Server (`pow.kashilo.com`), Fallback auf lokal |
## Häufige Befehle
@@ -90,8 +90,8 @@ docs/
├── MONETIZATION.md # Monetarisierung & Anti-Abuse
├── LAUNCH-PLAN.md # Release-Phasen, Pricing, Checkliste
├── REPUTATION.md # Reputation-System (Konzept, Directus-Anleitung)
├── pow-server/ # PHP PoW-Captcha Server (pow.dgray.io)
└── og-proxy.php # Open Graph Meta-Tag Proxy (pow.dgray.io)
├── pow-server/ # PHP PoW-Captcha Server (pow.kashilo.com)
└── og-proxy.php # Open Graph Meta-Tag Proxy (pow.kashilo.com)
css/
├── fonts.css # @font-face Definitionen (Inter, Space Grotesk)
@@ -163,10 +163,10 @@ locales/
1. ~~Seiten für Profil-Dropdown~~ ✅ Fertig
2. ~~Suchseite mit Filtern~~ ✅ Merged in `page-home.js`
3. ~~Listings bearbeiten~~ ✅ Edit-Modus via `#/edit/:id`
4. ~~PoW-Captcha server-seitig~~ ✅ PHP-Server auf `pow.dgray.io`
4. ~~PoW-Captcha server-seitig~~ ✅ PHP-Server auf `pow.kashilo.com`
5. ~~TweetNaCl self-hosted~~ ✅ In `js/vendor/`
6. ~~Chat-Crypto fix~~ ✅ Per-listing E2E Keys, TOFU Key-Pinning, kein Pending-Flow mehr
7. ~~Payment-Integration mit BTCpay Server~~ ✅ Proxy auf `pow.dgray.io`, Frontend-Service `btcpay.js`
7. ~~Payment-Integration mit BTCpay Server~~ ✅ Proxy auf `pow.kashilo.com`, Frontend-Service `btcpay.js`
8. ~~Favoriten Directus Sync~~ ✅ FavoritesService mit Union-Merge bei Login
9. ~~Expired Listings~~ ✅ Directus Flow (alle 15 Min), Status-Badges auf Cards
10. ~~Reputation-System~~`reputation.js` Service, Deals/Ratings Collections, Chat-Widget Deal-Bestätigung + Sterne-Bewertung, Seller-Card Badges (siehe `docs/REPUTATION.md`)

View File

@@ -1,10 +1,10 @@
# dgray.io
# kashilo.com
Eine anonyme, dezentrale Kleinanzeigen-Plattform mit Monero-Bezahlung.
## 🎯 Vision
dgray.io ermöglicht es Nutzern, Kleinanzeigen zu schalten und Waren/Dienstleistungen sicher über Monero (XMR) zu handeln. Besonderheiten:
kashilo.com ermöglicht es Nutzern, Kleinanzeigen zu schalten und Waren/Dienstleistungen sicher über Monero (XMR) zu handeln. Besonderheiten:
- **Anonymität**: Nutzung ohne Account möglich
- **Direkte Zahlung**: Peer-to-Peer via Monero, keine Zahlungsvermittlung
@@ -58,8 +58,8 @@ dgray.io ermöglicht es Nutzern, Kleinanzeigen zu schalten und Waren/Dienstleist
- Custom Extensions für XMR-Integration
### Services
- **Directus** Backend: `api.dgray.io` (Docker)
- **PoW Captcha + Payment Proxy**: `pow.dgray.io` (PHP, HMAC-signierte Challenges, BTCPay Proxy + Webhook, OG Meta Proxy)
- **Directus** Backend: `api.kashilo.com` (Docker)
- **PoW Captcha + Payment Proxy**: `pow.kashilo.com` (PHP, HMAC-signierte Challenges, BTCPay Proxy + Webhook, OG Meta Proxy)
- **BTCPay Server**: `pay.xmr.rocks` (Monero-Zahlungen, Trocador-Plugin)
- **TweetNaCl**: Self-hosted in `js/vendor/` (E2E-Verschlüsselung)
@@ -124,7 +124,7 @@ Das Build-Script minifiziert alle JS- und CSS-Dateien (~111 KiB Ersparnis) und k
```bash
# Einmalig: SSH-User und Pfad anpassen
./deploy.sh user@dgray.io /home/user/web/dgray.io/public_html
./deploy.sh user@kashilo.com /home/user/web/kashilo.com/public_html
# Oder Defaults im Script setzen und einfach:
./deploy.sh
@@ -152,7 +152,7 @@ Die Tests laufen im Browser und nutzen einen minimalen Test-Runner ohne externe
### Projektstruktur
```
dgray/
kashilo/
├── index.html # Entry Point
├── manifest.json # PWA Manifest
├── service-worker.js # Offline-Support
@@ -222,7 +222,7 @@ dgray/
- [ ] Responsive Optimierungen
### Phase 2: Backend-Integration ⬅️ **Aktuell**
- [x] Directus aufsetzen (`api.dgray.io`)
- [x] Directus aufsetzen (`api.kashilo.com`)
- [x] Listings-Collection (CRUD)
- [x] Categories mit Übersetzungen
- [x] User-Auth (UUID + SHA-256 Hash, anonym)
@@ -237,7 +237,7 @@ dgray/
- [x] Conversations/Messages Services
- [x] Merkliste (Favoriten-Seite)
- [x] Favoriten Directus-Sync (Union-Merge bei Login, localStorage-Fallback)
- [x] PoW Captcha (server-seitig via pow.dgray.io, HMAC-signiert)
- [x] PoW Captcha (server-seitig via pow.kashilo.com, HMAC-signiert)
- [x] TweetNaCl self-hosted (kein CDN)
- [x] In-App Benachrichtigungen (Notifications-Service, Glocke mit Badge)
- [x] Open Graph & X Card Meta-Tags (dynamisch pro Listing)
@@ -246,7 +246,7 @@ dgray/
### Phase 4: Payments
- [x] XMR-Kursabfrage API (CoinGecko)
- [x] Fiat ↔ XMR Umrechnung (Dual-Preis-Anzeige)
- [x] BTCPay Server Integration (`pay.xmr.rocks`, Proxy auf `pow.dgray.io`)
- [x] BTCPay Server Integration (`pay.xmr.rocks`, Proxy auf `pow.kashilo.com`)
- [x] Listing-Gebühr: 1 EUR/USD/CHF/GBP (200 JPY) via Monero
- [x] Webhook für Auto-Publish nach Blockchain-Confirmation
- [x] Expired Listings (Directus Flow, Status-Badges auf Cards)

View File

@@ -1,12 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 32">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 36">
<style>
.logo-text {
font-family: 'Space Grotesk', system-ui, sans-serif;
font-weight: 700;
font-size: 24px;
font-size: 30px;
}
</style>
<text x="4" y="24" class="logo-text">
<tspan fill="#10B981">d</tspan><tspan fill="#AAAAAA">gray</tspan>
<text x="2" y="28" class="logo-text">
<tspan fill="#10B981">k</tspan><tspan fill="#AAAAAA">ashilo</tspan>
</text>
</svg>

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 341 B

View File

@@ -1,12 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 32">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 36">
<style>
.logo-text {
font-family: 'Space Grotesk', system-ui, sans-serif;
font-weight: 700;
font-size: 24px;
font-size: 30px;
}
</style>
<text x="4" y="24" class="logo-text">
<tspan fill="#059669">d</tspan><tspan fill="#555555">gray</tspan>
<text x="2" y="28" class="logo-text">
<tspan fill="#059669">k</tspan><tspan fill="#555555">ashilo</tspan>
</text>
</svg>

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 341 B

View File

@@ -1,4 +1,4 @@
# dgray.io Press Kit
# kashilo.com Press Kit
## Brand Assets
@@ -35,7 +35,7 @@
## Verwendung
- Logo nicht verzerren, strecken oder recolorieren
- Mindestabstand: Höhe des "d" in "dgray" auf allen Seiten
- Mindestabstand: Höhe des "k" in "kashilo" auf allen Seiten
- Bevorzugt SVG verwenden
- Bei dunklem Hintergrund: `logo-light` verwenden
- Bei hellem Hintergrund: `logo-dark` verwenden
@@ -43,10 +43,10 @@
## Beschreibung (Copy & Paste)
**Kurz (1 Satz):**
dgray.io ist ein anonymer Kleinanzeigen-Marktplatz mit Monero-Bezahlung.
kashilo.com ist ein anonymer Kleinanzeigen-Marktplatz mit Monero-Bezahlung.
**Mittel (23 Sätze):**
dgray.io ermöglicht es, Waren und Dienstleistungen anonym zu handeln — bezahlt mit Monero (XMR). Kein KYC, keine E-Mail, keine persönlichen Daten. Kommunikation ist Ende-zu-Ende verschlüsselt.
kashilo.com ermöglicht es, Waren und Dienstleistungen anonym zu handeln — bezahlt mit Monero (XMR). Kein KYC, keine E-Mail, keine persönlichen Daten. Kommunikation ist Ende-zu-Ende verschlüsselt.
**Lang:**
dgray.io ist eine Privacy-First Kleinanzeigen-Plattform für den DACH-Raum. Nutzer können Anzeigen erstellen und über Ende-zu-Ende verschlüsselte Nachrichten kommunizieren — ohne persönliche Daten preiszugeben. Die Bezahlung erfolgt ausschließlich über Monero (XMR). Die Plattform erfordert keine E-Mail-Adresse, kein KYC und kein Tracking. Verfügbar als Progressive Web App in Deutsch, Englisch und Französisch.
kashilo.com ist eine Privacy-First Kleinanzeigen-Plattform für den DACH-Raum. Nutzer können Anzeigen erstellen und über Ende-zu-Ende verschlüsselte Nachrichten kommunizieren — ohne persönliche Daten preiszugeben. Die Bezahlung erfolgt ausschließlich über Monero (XMR). Die Plattform erfordert keine E-Mail-Adresse, kein KYC und kein Tracking. Verfügbar als Progressive Web App in Deutsch, Englisch und Französisch.

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
Build script for dgray.io
Build script for kashilo.com
Minifies JS and CSS files into dist/ directory.
Usage: python3 build.py

View File

@@ -1,6 +1,6 @@
:root {
/*
* Monochrome Theme - dgray.io
* Monochrome Theme - kashilo.com
* Pure grayscale with neon green accent
*/

View File

@@ -1,8 +1,8 @@
#!/bin/bash
# deploy.sh - Deploy dgray.io to production server via rsync
# deploy.sh - Deploy kashilo.com to production server via rsync
#
# Usage: ./deploy.sh [user@host] [remote-path]
# Example: ./deploy.sh admin@dgray.io /home/admin/web/dgray.io/public_html
# Example: ./deploy.sh admin@kashilo.com /home/admin/web/kashilo.com/public_html
#
# Prerequisites:
# - SSH key authentication configured
@@ -11,8 +11,8 @@
set -e
# --- Configuration ---
REMOTE_USER_HOST="${1:-admin@dgray.io}"
REMOTE_PATH="${2:-/home/admin/web/dgray.io/public_html}"
REMOTE_USER_HOST="${1:-admin@kashilo.com}"
REMOTE_PATH="${2:-/home/admin/web/kashilo.com/public_html}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DIST_DIR="$SCRIPT_DIR/dist"
@@ -22,7 +22,7 @@ python3 "$SCRIPT_DIR/build.py"
echo ""
# --- Deploy from dist/ ---
echo "Deploying dgray.io"
echo "Deploying kashilo.com"
echo " From: $DIST_DIR"
echo " To: $REMOTE_USER_HOST:$REMOTE_PATH"
echo ""

View File

@@ -2,7 +2,7 @@
**Directus Version:** 11.14.1
**Database:** PostgreSQL
**API Endpoint:** https://api.dgray.io
**API Endpoint:** https://api.kashilo.com
## Collections Overview

View File

@@ -1,8 +1,8 @@
# Directus Setup für dgray.io
# Directus Setup für kashilo.com
Komplette Anleitung zur Einrichtung von Directus als Backend für die dgray Kleinanzeigen-PWA.
Komplette Anleitung zur Einrichtung von Directus als Backend für die kashilo Kleinanzeigen-PWA.
**API URL**: https://api.dgray.io/
**API URL**: https://api.kashilo.com/
---
@@ -622,8 +622,8 @@ module.exports = async function(data, { database }) {
**Settings > Project Settings**
```
Project Name: dgray.io
Project URL: https://dgray.io
Project Name: kashilo.com
Project URL: https://kashilo.com
Project Color: #555555
```
@@ -637,7 +637,7 @@ services:
image: directus/directus:latest
environment:
CORS_ENABLED: "true"
CORS_ORIGIN: "https://dgray.io,https://www.dgray.io,http://localhost:8080"
CORS_ORIGIN: "https://kashilo.com,https://www.kashilo.com,http://localhost:8080"
CORS_METHODS: "GET,POST,PATCH,DELETE"
CORS_ALLOWED_HEADERS: "Content-Type,Authorization"
CORS_CREDENTIALS: "true"
@@ -655,7 +655,7 @@ services:
```env
# .env
CORS_ENABLED=true
CORS_ORIGIN=https://dgray.io,https://www.dgray.io,http://localhost:8080
CORS_ORIGIN=https://kashilo.com,https://www.kashilo.com,http://localhost:8080
CORS_METHODS=GET,POST,PATCH,DELETE
CORS_ALLOWED_HEADERS=Content-Type,Authorization
CORS_CREDENTIALS=true
@@ -706,7 +706,7 @@ environment:
STORAGE_S3_DRIVER: "s3"
STORAGE_S3_KEY: "your-access-key"
STORAGE_S3_SECRET: "your-secret-key"
STORAGE_S3_BUCKET: "dgray-files"
STORAGE_S3_BUCKET: "kashilo-files"
STORAGE_S3_REGION: "fsn1" # oder nbg1
STORAGE_S3_ENDPOINT: "https://fsn1.your-objectstorage.com" # oder nbg1
```
@@ -720,7 +720,7 @@ environment:
STORAGE_S3_DRIVER: "s3"
STORAGE_S3_KEY: "your-access-key"
STORAGE_S3_SECRET: "your-secret-key"
STORAGE_S3_BUCKET: "dgray-files"
STORAGE_S3_BUCKET: "kashilo-files"
STORAGE_S3_REGION: "auto"
STORAGE_S3_ENDPOINT: "https://xxx.r2.cloudflarestorage.com"
```
@@ -746,7 +746,7 @@ RATE_LIMITER_POINTS=100
RATE_LIMITER_DURATION=60
```
**Hinweis:** Keine E-Mail-Konfiguration nötig - dgray.io nutzt keine E-Mails (Privacy by Design).
**Hinweis:** Keine E-Mail-Konfiguration nötig - kashilo.com nutzt keine E-Mails (Privacy by Design).
### 5.6 Währungsumrechnung & Preismodus
@@ -901,7 +901,7 @@ if (directus.isAuthenticated()) {
## 9. Anonyme Authentifizierung (UUID-basiert)
Für maximale Privatsphäre nutzt dgray.io ein UUID-basiertes Login-System ohne echte E-Mail-Adressen.
Für maximale Privatsphäre nutzt kashilo.com ein UUID-basiertes Login-System ohne echte E-Mail-Adressen.
### 9.1 Konzept
@@ -913,7 +913,7 @@ Für maximale Privatsphäre nutzt dgray.io ein UUID-basiertes Login-System ohne
│ f47ac10b-58cc-4372-a567-0e02b2c3d479 │
│ ↓ │
│ Directus erhält: │
│ • E-Mail: f47ac10b-58cc-4372-a567-0e02b2c3d479@dgray.io
│ • E-Mail: f47ac10b-58cc-4372-a567-0e02b2c3d479@kashilo.com
│ • Passwort: f47ac10b-58cc-4372-a567-0e02b2c3d479 │
│ ↓ │
│ User speichert UUID → fertig │
@@ -943,7 +943,7 @@ Für maximale Privatsphäre nutzt dgray.io ein UUID-basiertes Login-System ohne
// Account erstellen
async function createAnonymousAccount() {
const uuid = crypto.randomUUID();
const email = `${uuid}@dgray.io`;
const email = `${uuid}@kashilo.com`;
const password = uuid;
// Bei Directus registrieren
@@ -957,7 +957,7 @@ async function createAnonymousAccount() {
// Login
async function login(uuid) {
const email = `${uuid}@dgray.io`;
const email = `${uuid}@kashilo.com`;
await directus.login(email, uuid);
}
```

View File

@@ -1,4 +1,4 @@
# Killer-Features — dgray.io
# Killer-Features — kashilo.com
Differenzierung gegenüber eBay Kleinanzeigen, Tutti, XMRBazaar.
Drei Features, die kein Konkurrent hat.

View File

@@ -1,4 +1,4 @@
# Launch Plan dgray.io
# Launch Plan kashilo.com
## Release-Phasen
@@ -48,12 +48,12 @@ Die Validierung passiert **serverseitig** im PoW-Server (PHP), nicht im Frontend
Neuer Endpoint: `POST /invite/validate`
```php
// pow.dgray.io/invite/validate.php
// pow.kashilo.com/invite/validate.php
<?php
require __DIR__ . '/config.php';
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://dgray.io');
header('Access-Control-Allow-Origin: https://kashilo.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
@@ -132,7 +132,7 @@ In `js/components/auth-modal.js` — im Registrierungs-Flow ein Textfeld hinzuf
Vor `createAccount()` den Code serverseitig validieren:
```js
const res = await fetch('https://pow.dgray.io/invite/validate', {
const res = await fetch('https://pow.kashilo.com/invite/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code: inviteCode })
@@ -214,21 +214,21 @@ define('LISTING_FEE', ['EUR' => 0.01, 'USD' => 0.01, 'CHF' => 0.01, 'GBP' => 0.0
## Meta-Tags (pro Sprache)
Die statischen Meta-Tags in `index.html` sind deutsch (Fallback).
Der OG-Proxy (`pow.dgray.io/og-proxy.php`) liefert Listing-spezifische Tags.
Der OG-Proxy (`pow.kashilo.com/og-proxy.php`) liefert Listing-spezifische Tags.
### Umgesetzte Texte
**Title:** `dgray.io [Sprache]`
**Title:** `kashilo.com [Sprache]`
| Sprache | Title | Description |
|---------|-------|-------------|
| **de** | dgray.io Anonyme Kleinanzeigen | Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat. |
| **en** | dgray.io Private Classifieds | Buy and sell without an account, without email. Pay with Monero. End-to-end encrypted chat. |
| **fr** | dgray.io Petites annonces anonymes | Achetez et vendez sans compte, sans e-mail. Paiement en Monero. Chat chiffré de bout en bout. |
| **it** | dgray.io Annunci anonimi | Compra e vendi senza account, senza email. Pagamento in Monero. Chat crittografata end-to-end. |
| **es** | dgray.io Clasificados anónimos | Compra y vende sin cuenta, sin email. Pago con Monero. Chat cifrado de extremo a extremo. |
| **pt** | dgray.io Classificados anônimos | Compre e venda sem conta, sem email. Pagamento com Monero. Chat criptografado ponta a ponta. |
| **ru** | dgray.io Анонимные объявления | Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата. |
| **de** | kashilo.com Anonyme Kleinanzeigen | Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat. |
| **en** | kashilo.com Private Classifieds | Buy and sell without an account, without email. Pay with Monero. End-to-end encrypted chat. |
| **fr** | kashilo.com Petites annonces anonymes | Achetez et vendez sans compte, sans e-mail. Paiement en Monero. Chat chiffré de bout en bout. |
| **it** | kashilo.com Annunci anonimi | Compra e vendi senza account, senza email. Pagamento in Monero. Chat crittografata end-to-end. |
| **es** | kashilo.com Clasificados anónimos | Compra y vende sin cuenta, sin email. Pago con Monero. Chat cifrado de extremo a extremo. |
| **pt** | kashilo.com Classificados anônimos | Compre e venda sem conta, sem email. Pagamento com Monero. Chat criptografado ponta a ponta. |
| **ru** | kashilo.com Анонимные объявления | Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата. |
### Umsetzung
@@ -244,7 +244,7 @@ und `twitter:title/description` dynamisch bei jedem Sprachwechsel (i18n-Keys `me
## Checkliste vor Alpha-Start
- [ ] Directus: Collection `invite_codes` anlegen (Schema siehe oben)
- [ ] PHP: `invite/validate.php` deployen auf `pow.dgray.io`
- [ ] PHP: `invite/validate.php` deployen auf `pow.kashilo.com`
- [ ] PHP: `config.php``LISTING_FEE` auf 0.01 setzen
- [ ] PHP: `config.php``REQUIRE_INVITE_CODE = true`
- [ ] Frontend: Invite-Code-Feld in `auth-modal.js` einbauen

View File

@@ -1,4 +1,4 @@
# Marketing-Strategie dgray.io
# Marketing-Strategie kashilo.com
## Positionierung
@@ -43,7 +43,7 @@
### Woche 5: Name Reveal
- **Post 7:** Logo + Name + "dgray.io — Anonymous classifieds. Powered by Monero. Beta coming next week."
- **Post 7:** Logo + Name + "kashilo.com — Anonymous classifieds. Powered by Monero. Beta coming next week."
- Landing Page live schalten (optional, kann auch direkt die App sein)
- Einmalig in relevanten Subreddits posten: r/Monero, r/privacy, r/selfhosted
@@ -58,10 +58,10 @@
- **Ziel:** Echte Listings generieren, Feedback sammeln, Bugs finden
**Launch-Post auf X:**
> "dgray.io is live in beta. 🔒 Anonymous classifieds with Monero.
> "kashilo.com is live in beta. 🔒 Anonymous classifieds with Monero.
> First 100 listings for just 0.10 EUR.
> No KYC. No email. No tracking. E2E encrypted chat.
> Try it: https://dgray.io"
> Try it: https://kashilo.com"
### Weitere Launch-Kanäle
@@ -83,7 +83,7 @@
- **Weekly Update** auf X: Neue Features, Stats (wenn Schwellwert erreicht)
- **Build in Public:** Entwicklungsfortschritte teilen
- **User Stories:** Erfolgreiche Deals highlighten (anonym natürlich)
- **Vergleiche:** "Why we built dgray.io" — Vergleich mit KYC-Plattformen
- **Vergleiche:** "Why we built kashilo.com" — Vergleich mit KYC-Plattformen
### Community
@@ -123,7 +123,7 @@
| XmrBazaar | Etabliert, 7800 User | Spam, altbackenes Design, nur EN |
| Bitejo | Dezentral | Wenig Nutzer |
| MoneroMarket | Einfach | Kaum Features |
| **dgray.io** | Modern, lokal, E2E, PWA | Neu, noch keine User |
| **kashilo.com** | Modern, lokal, E2E, PWA | Neu, noch keine User |
---

View File

@@ -1,4 +1,4 @@
# Monetarisierung - dgray.io
# Monetarisierung - kashilo.com
## Preismodell
@@ -50,7 +50,7 @@
- **Provider**: BTCpay Server (self-hosted)
- **URL**: https://pay.xmr.rocks/
- **Proxy**: `pow.dgray.io` — alle API-Aufrufe laufen über den PHP-Proxy (BTCPay API-Key bleibt serverseitig)
- **Proxy**: `pow.kashilo.com` — alle API-Aufrufe laufen über den PHP-Proxy (BTCPay API-Key bleibt serverseitig)
- **Primär**: Monero (XMR)
- **Alternativ**: Andere Kryptos via Trocador-Plugin (automatischer Swap zu XMR)
- **Preisumrechnung**: Live XMR-Kurs via Kraken API
@@ -60,14 +60,14 @@
### Flow: Draft → Processing → Published
1. User erstellt Listing → wird als `draft` mit `payment_status: unpaid` gespeichert
2. BTCPay Invoice wird über `pow.dgray.io/btcpay/invoice` erstellt
2. BTCPay Invoice wird über `pow.kashilo.com/btcpay/invoice` erstellt
3. BTCPay Checkout-Modal öffnet sich im Frontend (`js/services/btcpay.js`)
4. Nach Zahlung:
- **Frontend**: Prüft Status via `pow.dgray.io/btcpay/status` nach Modal-Close
- **Webhook**: `pow.dgray.io/btcpay/webhook` empfängt BTCPay Events, setzt `status: published` + `payment_status: paid` nach 1 Confirmation
- **Frontend**: Prüft Status via `pow.kashilo.com/btcpay/status` nach Modal-Close
- **Webhook**: `pow.kashilo.com/btcpay/webhook` empfängt BTCPay Events, setzt `status: published` + `payment_status: paid` nach 1 Confirmation
5. Listing wird veröffentlicht (30 Tage Laufzeit, `expires_at` wird gesetzt)
### Endpunkte (pow.dgray.io)
### Endpunkte (pow.kashilo.com)
| Endpoint | Methode | Beschreibung |
|----------|---------|-------------|
@@ -81,5 +81,5 @@
- [x] ~~XMR-Kurs API für Umrechnung~~ → Kraken API
- [x] ~~Anzahl Deals für Power-User Status~~ → 5/15/50 Stufen
- [x] ~~Captcha-Lösung~~ → Eigenes PoW-Captcha (keine Lizenzkosten)
- [x] ~~Payment-Proxy~~`pow.dgray.io` (PHP, API-Key serverseitig)
- [x] ~~Webhook für Auto-Publish~~`btcpay-webhook.php` auf `pow.dgray.io`
- [x] ~~Payment-Proxy~~`pow.kashilo.com` (PHP, API-Key serverseitig)
- [x] ~~Webhook für Auto-Publish~~`btcpay-webhook.php` auf `pow.kashilo.com`

View File

@@ -1,13 +1,13 @@
# Datenschutzerklärung
**dgray.io — Anonymer Marktplatz**
**kashilo.com — Anonymer Marktplatz**
Stand: Februar 2026
---
## 1. Verantwortlicher
Verantwortlich für die Datenbearbeitung ist der Betreiber der Plattform dgray.io mit Sitz in der Schweiz.
Verantwortlich für die Datenbearbeitung ist der Betreiber der Plattform kashilo.com mit Sitz in der Schweiz.
---

View File

@@ -1,4 +1,4 @@
# Reputation-System — dgray.io
# Reputation-System — kashilo.com
## Ziel

View File

@@ -1,13 +1,13 @@
# Allgemeine Geschäftsbedingungen (AGB)
**dgray.io — Anonymer Marktplatz**
**kashilo.com — Anonymer Marktplatz**
Stand: Februar 2026
---
## 1. Geltungsbereich
1.1 Diese Allgemeinen Geschäftsbedingungen (nachfolgend «AGB») regeln die Nutzung der Plattform dgray.io (nachfolgend «Plattform»).
1.1 Diese Allgemeinen Geschäftsbedingungen (nachfolgend «AGB») regeln die Nutzung der Plattform kashilo.com (nachfolgend «Plattform»).
1.2 Die Plattform wird betrieben von einer natürlichen Person mit Sitz in der Schweiz (nachfolgend «Betreiber»).

View File

@@ -5,7 +5,7 @@
# This script adds it-IT, es-ES, pt-BR, ru-RU translations to all categories.
# It reads existing categories from the API and creates missing translations.
API="https://api.dgray.io"
API="https://api.kashilo.com"
TOKEN="${DIRECTUS_TOKEN:?Set DIRECTUS_TOKEN environment variable}"
add_translation() {

View File

@@ -1,8 +1,8 @@
#!/bin/bash
# Bulk-Import: All categories for dgray.io
# Bulk-Import: All categories for kashilo.com
# Usage: DIRECTUS_TOKEN=your_admin_token bash docs/import-categories.sh
API="https://api.dgray.io"
API="https://api.kashilo.com"
TOKEN="${DIRECTUS_TOKEN:?Set DIRECTUS_TOKEN environment variable}"
create_category() {

View File

@@ -1,10 +1,10 @@
# PoW Captcha & Payment Server
PHP-basierter Server für dgray.io mit Proof-of-Work Captcha und BTCPay Payment-Proxy.
PHP-basierter Server für kashilo.com mit Proof-of-Work Captcha und BTCPay Payment-Proxy.
## Setup
1. Subdomain `pow.dgray.io` auf den Server zeigen
1. Subdomain `pow.kashilo.com` auf den Server zeigen
2. Dateien in das Web-Root kopieren
3. Secrets setzen:
```bash
@@ -18,10 +18,10 @@ PHP-basierter Server für dgray.io mit Proof-of-Work Captcha und BTCPay Payment-
4. Testen:
```bash
# PoW Challenge
curl https://pow.dgray.io/challenge
curl https://pow.kashilo.com/challenge
# BTCPay Invoice erstellen
curl -X POST https://pow.dgray.io/btcpay/invoice \
curl -X POST https://pow.kashilo.com/btcpay/invoice \
-H "Content-Type: application/json" \
-d '{"listingId": "test-123", "currency": "EUR"}'
```
@@ -76,7 +76,7 @@ Response:
### POST /btcpay/webhook
Empfängt BTCPay Server Webhook-Events. Wird in BTCPay unter Store → Settings → Webhooks konfiguriert.
- **URL**: `https://pow.dgray.io/btcpay/webhook`
- **URL**: `https://pow.kashilo.com/btcpay/webhook`
- **Event**: `InvoiceSettled` (nach 1 Blockchain-Confirmation)
- **Aktion**: Setzt das zugehörige Listing in Directus auf `status: published`, `payment_status: paid`, setzt `paid_at` und `expires_at` (30 Tage)
- **Sicherheit**: Webhook-Secret wird serverseitig geprüft
@@ -95,7 +95,7 @@ Empfängt BTCPay Server Webhook-Events. Wird in BTCPay unter Store → Settings
- HMAC-SHA256 signierte Challenges (nicht fälschbar)
- TTL: 2 Minuten
- CORS: nur `https://dgray.io`
- CORS: nur `https://kashilo.com`
- `hash_equals()` gegen Timing-Attacks
- BTCPay API-Key bleibt serverseitig (nie im Frontend)
- Gebühren serverseitig erzwungen (nicht manipulierbar)

View File

@@ -9,5 +9,5 @@ define('BTCPAY_STORE_ID', getenv('BTCPAY_STORE_ID') ?: 'CHANGE_ME');
define('BTCPAY_WEBHOOK_SECRET', getenv('BTCPAY_WEBHOOK_SECRET') ?: '');
define('LISTING_FEE', ['EUR' => 1, 'USD' => 1, 'CHF' => 1, 'GBP' => 1, 'JPY' => 200]);
define('DIRECTUS_URL', getenv('DIRECTUS_URL') ?: 'https://api.dgray.io');
define('DIRECTUS_URL', getenv('DIRECTUS_URL') ?: 'https://api.kashilo.com');
define('DIRECTUS_TOKEN', getenv('DIRECTUS_TOKEN') ?: 'CHANGE_ME');

View File

@@ -1,12 +1,12 @@
<?php
header('Content-Type: application/json');
$allowedOrigins = ['https://dgray.io', 'http://localhost:5500', 'http://localhost:8080'];
$allowedOrigins = ['https://kashilo.com', 'http://localhost:5500', 'http://localhost:8080'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header('Access-Control-Allow-Origin: ' . $origin);
} else {
header('Access-Control-Allow-Origin: https://dgray.io');
header('Access-Control-Allow-Origin: https://kashilo.com');
}
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');

View File

@@ -2,14 +2,14 @@
/**
* OG Meta Tag Proxy for Social Media Crawlers
*
* Setup: Nginx/Apache rewrite rule on dgray.io:
* Setup: Nginx/Apache rewrite rule on kashilo.com:
* If User-Agent matches crawler → proxy to this script
* Else → serve static index.html
*
* Example Apache config (in VHost):
* RewriteEngine On
* RewriteCond %{HTTP_USER_AGENT} Twitterbot|facebookexternalhit|TelegramBot|Discordbot|Slackbot|WhatsApp [NC]
* RewriteRule ^/listing/(.*)$ https://pow.dgray.io/og-proxy.php?listing=$1 [P,L]
* RewriteRule ^/listing/(.*)$ https://pow.kashilo.com/og-proxy.php?listing=$1 [P,L]
*
* Required modules: sudo a2enmod rewrite proxy proxy_http
*
@@ -17,7 +17,7 @@
* location /listing/ {
* if ($http_user_agent ~* "Twitterbot|facebookexternalhit|TelegramBot|Discordbot|Slackbot|WhatsApp") {
* rewrite ^/listing/(.*)$ /og-proxy.php?listing=$1 break;
* proxy_pass https://pow.dgray.io;
* proxy_pass https://pow.kashilo.com;
* }
* }
*
@@ -40,8 +40,8 @@ if (!$listingId && isset($_GET['listing'])) {
$listingId = $_GET['listing'];
}
$siteUrl = 'https://dgray.io';
$defaultTitle = 'dgray.io Anonymous Classifieds with Monero';
$siteUrl = 'https://kashilo.com';
$defaultTitle = 'kashilo.com Anonymous Classifieds with Monero';
$defaultDesc = 'Buy and sell anonymously with Monero. No KYC, no email, E2E encrypted chat.';
$defaultImage = $siteUrl . '/assets/press/og-image.png';
@@ -70,7 +70,7 @@ if ($listingId) {
$listing = $data['data'] ?? null;
if ($listing) {
$title = htmlspecialchars($listing['title'] ?? '') . ' dgray.io';
$title = htmlspecialchars($listing['title'] ?? '') . ' kashilo.com';
$description = htmlspecialchars(mb_substr($listing['description'] ?? '', 0, 160));
$url = $siteUrl . '/#/listing/' . $listing['id'];
$type = 'product';
@@ -101,7 +101,7 @@ header('Content-Type: text/html; charset=utf-8');
<!-- Open Graph -->
<meta property="og:type" content="<?= $type ?>">
<meta property="og:site_name" content="dgray.io">
<meta property="og:site_name" content="kashilo.com">
<meta property="og:title" content="<?= $title ?>">
<meta property="og:description" content="<?= $description ?>">
<meta property="og:url" content="<?= $url ?>">

View File

@@ -6,15 +6,15 @@
<meta name="description" content="Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat.">
<meta name="theme-color" content="#555555">
<title>dgray.io Anonyme Kleinanzeigen</title>
<title>kashilo.com Anonyme Kleinanzeigen</title>
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="dgray.io">
<meta property="og:title" content="dgray.io Anonyme Kleinanzeigen">
<meta property="og:site_name" content="kashilo.com">
<meta property="og:title" content="kashilo.com Anonyme Kleinanzeigen">
<meta property="og:description" content="Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat.">
<meta property="og:url" content="https://dgray.io">
<meta property="og:image" content="https://dgray.io/assets/press/og-image.png">
<meta property="og:url" content="https://kashilo.com">
<meta property="og:image" content="https://kashilo.com/assets/press/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:locale" content="de_DE">
@@ -23,9 +23,9 @@
<!-- X (Twitter) Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="dgray.io Anonyme Kleinanzeigen">
<meta name="twitter:title" content="kashilo.com Anonyme Kleinanzeigen">
<meta name="twitter:description" content="Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat.">
<meta name="twitter:image" content="https://dgray.io/assets/press/og-image.png">
<meta name="twitter:image" content="https://kashilo.com/assets/press/og-image.png">
<link rel="manifest" href="manifest.json">
<link rel="icon" type="image/svg+xml" href="assets/icon-light.svg" media="(prefers-color-scheme: light)">
@@ -154,7 +154,7 @@
<app-footer>
<div class="footer-inner container">
<p class="footer-copyright">
&copy; 2026 dgray.io - <span data-i18n="footer.rights">Alle Rechte vorbehalten.</span>
&copy; 2026 kashilo.com - <span data-i18n="footer.rights">Alle Rechte vorbehalten.</span>
<span class="footer-swiss">🇨🇭 Made in Switzerland</span>
</p>
<span class="xmr-rate" title="CoinGecko">1 XMR ≈ ...</span>

View File

@@ -26,7 +26,7 @@ class AppFooter extends HTMLElement {
}
getCurrency() {
return localStorage.getItem('dgray_currency') || 'USD'
return localStorage.getItem('kashilo_currency') || 'USD'
}
async loadXmrRates() {
@@ -54,7 +54,7 @@ class AppFooter extends HTMLElement {
this.innerHTML = /* html */`
<div class="footer-inner container">
<p class="footer-copyright">
&copy; ${year} dgray.io - <span data-i18n="footer.rights">${t('footer.rights')}</span>
&copy; ${year} kashilo.com - <span data-i18n="footer.rights">${t('footer.rights')}</span>
<span class="footer-swiss">🇨🇭 Made in Switzerland</span>
</p>
<span class="xmr-rate" title="CoinGecko">1 XMR ≈ ...</span>

View File

@@ -113,9 +113,9 @@ class AppHeader extends HTMLElement {
render() {
this.innerHTML = /* html */`
<div class="header-inner container">
<a href="#/" class="logo" aria-label="dgray.io ${t('common.home')}">
<img src="assets/logo-light.svg" alt="dgray.io" class="logo-img logo-light" width="100" height="28">
<img src="assets/logo-dark.svg" alt="dgray.io" class="logo-img logo-dark" width="100" height="28">
<a href="#/" class="logo" aria-label="kashilo.com ${t('common.home')}">
<img src="assets/logo-light.svg" alt="kashilo.com" class="logo-img logo-light" width="100" height="28">
<img src="assets/logo-dark.svg" alt="kashilo.com" class="logo-img logo-dark" width="100" height="28">
</a>
<div class="header-actions">

View File

@@ -319,14 +319,14 @@ class AuthModal extends HTMLElement {
}
downloadBackup() {
const content = `dgray.io Account Backup
const content = `kashilo.com Account Backup
========================
Your UUID (keep this secret!):
${this.generatedUuid}
Login URL:
https://dgray.io/#/login
https://kashilo.com/#/login
Created: ${new Date().toISOString()}
@@ -337,7 +337,7 @@ WARNING: If you lose this UUID, you cannot recover your account!
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `dgray-backup-${this.generatedUuid.slice(0, 8)}.txt`
a.download = `kashilo-backup-${this.generatedUuid.slice(0, 8)}.txt`
a.click()
URL.revokeObjectURL(url)
}

View File

@@ -144,7 +144,7 @@ class LocationMap extends HTMLElement {
})
const response = await fetch(`${NOMINATIM_URL}?${params}`, {
headers: { 'User-Agent': 'dgray.io/1.0' }
headers: { 'User-Agent': 'kashilo.com/1.0' }
})
const results = await response.json()

View File

@@ -183,7 +183,7 @@ class LocationPicker extends HTMLElement {
const response = await fetch(`${NOMINATIM_URL}?${params}`, {
headers: {
'User-Agent': 'dgray.io/1.0'
'User-Agent': 'kashilo.com/1.0'
}
})

View File

@@ -15,8 +15,8 @@ class PageAbout extends HTMLElement {
getContent(lang) {
const content = {
de: /* html */`
<h1>Über dgray.io</h1>
<p>dgray.io ist eine Privacy-First Kleinanzeigen-Plattform. Nutzer können Anzeigen erstellen und über Ende-zu-Ende verschlüsselte Nachrichten kommunizieren — ohne persönliche Daten preiszugeben.</p>
<h1>Über kashilo.com</h1>
<p>kashilo.com ist eine Privacy-First Kleinanzeigen-Plattform. Nutzer können Anzeigen erstellen und über Ende-zu-Ende verschlüsselte Nachrichten kommunizieren — ohne persönliche Daten preiszugeben.</p>
<p>Die Bezahlung erfolgt ausschliesslich über Monero (XMR). Kein KYC, keine E-Mail, kein Tracking.</p>
<h2>Prinzipien</h2>
@@ -29,8 +29,8 @@ class PageAbout extends HTMLElement {
</ul>
`,
en: /* html */`
<h1>About dgray.io</h1>
<p>dgray.io is a privacy-first classifieds platform. Users can create listings and communicate via end-to-end encrypted messages — without revealing any personal data.</p>
<h1>About kashilo.com</h1>
<p>kashilo.com is a privacy-first classifieds platform. Users can create listings and communicate via end-to-end encrypted messages — without revealing any personal data.</p>
<p>Payments are made exclusively in Monero (XMR). No KYC, no email, no tracking.</p>
<h2>Principles</h2>
@@ -43,8 +43,8 @@ class PageAbout extends HTMLElement {
</ul>
`,
fr: /* html */`
<h1>À propos de dgray.io</h1>
<p>dgray.io est une plateforme de petites annonces axée sur la confidentialité. Les utilisateurs peuvent créer des annonces et communiquer via des messages chiffrés de bout en bout — sans révéler de données personnelles.</p>
<h1>À propos de kashilo.com</h1>
<p>kashilo.com est une plateforme de petites annonces axée sur la confidentialité. Les utilisateurs peuvent créer des annonces et communiquer via des messages chiffrés de bout en bout — sans révéler de données personnelles.</p>
<p>Les paiements s'effectuent exclusivement en Monero (XMR). Pas de KYC, pas d'e-mail, pas de tracking.</p>
<h2>Principes</h2>
@@ -57,8 +57,8 @@ class PageAbout extends HTMLElement {
</ul>
`,
it: /* html */`
<h1>Informazioni su dgray.io</h1>
<p>dgray.io è una piattaforma di annunci incentrata sulla privacy. Gli utenti possono creare annunci e comunicare tramite messaggi crittografati end-to-end — senza rivelare dati personali.</p>
<h1>Informazioni su kashilo.com</h1>
<p>kashilo.com è una piattaforma di annunci incentrata sulla privacy. Gli utenti possono creare annunci e comunicare tramite messaggi crittografati end-to-end — senza rivelare dati personali.</p>
<p>I pagamenti avvengono esclusivamente in Monero (XMR). Nessun KYC, nessuna email, nessun tracking.</p>
<h2>Principi</h2>
@@ -71,8 +71,8 @@ class PageAbout extends HTMLElement {
</ul>
`,
es: /* html */`
<h1>Acerca de dgray.io</h1>
<p>dgray.io es una plataforma de clasificados centrada en la privacidad. Los usuarios pueden crear anuncios y comunicarse mediante mensajes cifrados de extremo a extremo — sin revelar datos personales.</p>
<h1>Acerca de kashilo.com</h1>
<p>kashilo.com es una plataforma de clasificados centrada en la privacidad. Los usuarios pueden crear anuncios y comunicarse mediante mensajes cifrados de extremo a extremo — sin revelar datos personales.</p>
<p>Los pagos se realizan exclusivamente en Monero (XMR). Sin KYC, sin email, sin rastreo.</p>
<h2>Principios</h2>
@@ -85,8 +85,8 @@ class PageAbout extends HTMLElement {
</ul>
`,
pt: /* html */`
<h1>Sobre o dgray.io</h1>
<p>dgray.io é uma plataforma de classificados focada em privacidade. Os usuários podem criar anúncios e se comunicar por mensagens criptografadas de ponta a ponta — sem revelar dados pessoais.</p>
<h1>Sobre o kashilo.com</h1>
<p>kashilo.com é uma plataforma de classificados focada em privacidade. Os usuários podem criar anúncios e se comunicar por mensagens criptografadas de ponta a ponta — sem revelar dados pessoais.</p>
<p>Os pagamentos são feitos exclusivamente em Monero (XMR). Sem KYC, sem email, sem rastreamento.</p>
<h2>Princípios</h2>
@@ -99,8 +99,8 @@ class PageAbout extends HTMLElement {
</ul>
`,
ru: /* html */`
<h1>О dgray.io</h1>
<p>dgray.io — это платформа объявлений с приоритетом конфиденциальности. Пользователи могут создавать объявления и общаться через сквозное шифрование — без раскрытия личных данных.</p>
<h1>О kashilo.com</h1>
<p>kashilo.com — это платформа объявлений с приоритетом конфиденциальности. Пользователи могут создавать объявления и общаться через сквозное шифрование — без раскрытия личных данных.</p>
<p>Оплата осуществляется исключительно в Monero (XMR). Без KYC, без email, без отслеживания.</p>
<h2>Принципы</h2>

View File

@@ -17,17 +17,17 @@ class PageContact extends HTMLElement {
de: /* html */`
<h1>Kontakt</h1>
<p>Bei Fragen oder Problemen erreichst du uns unter:</p>
<p><strong>E-Mail:</strong> <a href="mailto:hello@dgray.io">hello@dgray.io</a></p>
<p><strong>E-Mail:</strong> <a href="mailto:hello@kashilo.com">hello@kashilo.com</a></p>
`,
en: /* html */`
<h1>Contact</h1>
<p>For questions or issues, reach us at:</p>
<p><strong>Email:</strong> <a href="mailto:hello@dgray.io">hello@dgray.io</a></p>
<p><strong>Email:</strong> <a href="mailto:hello@kashilo.com">hello@kashilo.com</a></p>
`,
fr: /* html */`
<h1>Contact</h1>
<p>Pour toute question ou problème, contactez-nous à :</p>
<p><strong>E-mail :</strong> <a href="mailto:hello@dgray.io">hello@dgray.io</a></p>
<p><strong>E-mail :</strong> <a href="mailto:hello@kashilo.com">hello@kashilo.com</a></p>
`
}
return content[lang] || content.de

View File

@@ -12,7 +12,7 @@ import '../location-picker.js'
import '../pow-captcha.js'
import '../image-cropper.js'
const STORAGE_KEY = 'dgray_create_draft'
const STORAGE_KEY = 'kashilo_create_draft'
class PageCreate extends HTMLElement {
constructor() {

View File

@@ -17,7 +17,7 @@ class PageImprint extends HTMLElement {
de: /* html */`
<h1>Impressum</h1>
<div class="legal-draft-notice">ENTWURF — Bitte durch eine Fachperson prüfen lassen.</div>
<p class="legal-meta">dgray.io — Anonymer Marktplatz | Stand: Februar 2026</p>
<p class="legal-meta">kashilo.com — Anonymer Marktplatz | Stand: Februar 2026</p>
<h2>1. Angaben gemäss Schweizer Recht</h2>
<p>Verantwortlich für diese Website:</p>
@@ -49,7 +49,7 @@ class PageImprint extends HTMLElement {
en: /* html */`
<h1>Legal Notice</h1>
<div class="legal-draft-notice">DRAFT — Please have this reviewed by a legal professional.</div>
<p class="legal-meta">dgray.io — Anonymous Marketplace | Last updated: February 2026</p>
<p class="legal-meta">kashilo.com — Anonymous Marketplace | Last updated: February 2026</p>
<h2>1. Information according to Swiss law</h2>
<p>Responsible for this website:</p>
@@ -81,7 +81,7 @@ class PageImprint extends HTMLElement {
fr: /* html */`
<h1>Mentions légales</h1>
<div class="legal-draft-notice">ÉBAUCHE — Veuillez faire vérifier ce document par un professionnel du droit.</div>
<p class="legal-meta">dgray.io — Marché anonyme | Mise à jour : février 2026</p>
<p class="legal-meta">kashilo.com — Marché anonyme | Mise à jour : février 2026</p>
<h2>1. Informations selon le droit suisse</h2>
<p>Responsable de ce site web :</p>
@@ -113,7 +113,7 @@ class PageImprint extends HTMLElement {
it: /* html */`
<h1>Avviso legale</h1>
<div class="legal-draft-notice">BOZZA — Si prega di far verificare questo documento da un professionista legale.</div>
<p class="legal-meta">dgray.io — Mercato anonimo | Aggiornamento: febbraio 2026</p>
<p class="legal-meta">kashilo.com — Mercato anonimo | Aggiornamento: febbraio 2026</p>
<h2>1. Informazioni secondo il diritto svizzero</h2>
<p>Responsabile di questo sito web:</p>
@@ -145,7 +145,7 @@ class PageImprint extends HTMLElement {
es: /* html */`
<h1>Aviso legal</h1>
<div class="legal-draft-notice">BORRADOR — Por favor, haga revisar este documento por un profesional legal.</div>
<p class="legal-meta">dgray.io — Mercado anónimo | Actualización: febrero 2026</p>
<p class="legal-meta">kashilo.com — Mercado anónimo | Actualización: febrero 2026</p>
<h2>1. Información según la legislación suiza</h2>
<p>Responsable de este sitio web:</p>
@@ -177,7 +177,7 @@ class PageImprint extends HTMLElement {
pt: /* html */`
<h1>Aviso legal</h1>
<div class="legal-draft-notice">RASCUNHO — Por favor, solicite a revisão deste documento por um profissional jurídico.</div>
<p class="legal-meta">dgray.io — Mercado anônimo | Atualização: fevereiro 2026</p>
<p class="legal-meta">kashilo.com — Mercado anônimo | Atualização: fevereiro 2026</p>
<h2>1. Informações conforme a legislação suíça</h2>
<p>Responsável por este site:</p>
@@ -209,7 +209,7 @@ class PageImprint extends HTMLElement {
ru: /* html */`
<h1>Правовая информация</h1>
<div class="legal-draft-notice">ЧЕРНОВИК — Пожалуйста, передайте этот документ на проверку юристу.</div>
<p class="legal-meta">dgray.io — Анонимный маркетплейс | Обновлено: февраль 2026</p>
<p class="legal-meta">kashilo.com — Анонимный маркетплейс | Обновлено: февраль 2026</p>
<h2>1. Сведения согласно швейцарскому праву</h2>
<p>Ответственный за данный сайт:</p>

View File

@@ -90,11 +90,11 @@ class PageListing extends HTMLElement {
updateMetaTags() {
if (!this.listing) return
const title = `${this.listing.title} dgray.io`
const title = `${this.listing.title} kashilo.com`
const description = (this.listing.description || '').substring(0, 160)
const imageId = this.listing.images?.[0]?.directus_files_id?.id || this.listing.images?.[0]?.directus_files_id
const imageUrl = imageId ? directus.getFileUrl(imageId, { width: 1200, height: 630, fit: 'cover' }) : 'https://dgray.io/assets/press/og-image.png'
const url = `https://dgray.io/#/listing/${this.listing.id}`
const imageUrl = imageId ? directus.getFileUrl(imageId, { width: 1200, height: 630, fit: 'cover' }) : 'https://kashilo.com/assets/press/og-image.png'
const url = `https://kashilo.com/#/listing/${this.listing.id}`
document.title = title
this._setMeta('description', description)
@@ -109,16 +109,16 @@ class PageListing extends HTMLElement {
}
resetMetaTags() {
const defaultTitle = 'dgray.io Anonymous Classifieds with Monero'
const defaultTitle = 'kashilo.com Anonymous Classifieds with Monero'
const defaultDesc = 'Buy and sell anonymously with Monero. No KYC, no email, E2E encrypted chat.'
const defaultImage = 'https://dgray.io/assets/press/og-image.png'
const defaultImage = 'https://kashilo.com/assets/press/og-image.png'
document.title = defaultTitle
this._setMeta('description', defaultDesc)
this._setMeta('og:title', defaultTitle, true)
this._setMeta('og:description', defaultDesc, true)
this._setMeta('og:image', defaultImage, true)
this._setMeta('og:url', 'https://dgray.io', true)
this._setMeta('og:url', 'https://kashilo.com', true)
this._setMeta('og:type', 'website', true)
this._setMeta('twitter:title', defaultTitle)
this._setMeta('twitter:description', defaultDesc)

View File

@@ -16,10 +16,10 @@ class PagePrivacy extends HTMLElement {
const content = {
de: /* html */`
<h1>Datenschutzerklärung</h1>
<p class="legal-meta">dgray.io — Anonymer Marktplatz | Stand: Februar 2026</p>
<p class="legal-meta">kashilo.com — Anonymer Marktplatz | Stand: Februar 2026</p>
<h2>1. Verantwortlicher</h2>
<p>Verantwortlich für die Datenbearbeitung ist der Betreiber der Plattform dgray.io mit Sitz in der Schweiz.</p>
<p>Verantwortlich für die Datenbearbeitung ist der Betreiber der Plattform kashilo.com mit Sitz in der Schweiz.</p>
<h2>2. Grundsatz</h2>
<p>Die Plattform wurde nach dem Prinzip der Datensparsamkeit konzipiert.</p>
@@ -67,10 +67,10 @@ class PagePrivacy extends HTMLElement {
`,
en: /* html */`
<h1>Privacy Policy</h1>
<p class="legal-meta">dgray.io — Anonymous Marketplace | Last updated: February 2026</p>
<p class="legal-meta">kashilo.com — Anonymous Marketplace | Last updated: February 2026</p>
<h2>1. Controller</h2>
<p>The controller for data processing is the operator of dgray.io, based in Switzerland.</p>
<p>The controller for data processing is the operator of kashilo.com, based in Switzerland.</p>
<h2>2. Principle</h2>
<p>The platform was designed following the principle of data minimization.</p>
@@ -118,10 +118,10 @@ class PagePrivacy extends HTMLElement {
`,
fr: /* html */`
<h1>Politique de confidentialité</h1>
<p class="legal-meta">dgray.io — Marché anonyme | Mise à jour : février 2026</p>
<p class="legal-meta">kashilo.com — Marché anonyme | Mise à jour : février 2026</p>
<h2>1. Responsable</h2>
<p>Le responsable du traitement des données est l'exploitant de dgray.io, domicilié en Suisse.</p>
<p>Le responsable du traitement des données est l'exploitant de kashilo.com, domicilié en Suisse.</p>
<h2>2. Principe</h2>
<p>La plateforme a été conçue selon le principe de minimisation des données.</p>
@@ -169,10 +169,10 @@ class PagePrivacy extends HTMLElement {
`,
it: /* html */`
<h1>Informativa sulla privacy</h1>
<p class="legal-meta">dgray.io — Mercato anonimo | Aggiornamento: febbraio 2026</p>
<p class="legal-meta">kashilo.com — Mercato anonimo | Aggiornamento: febbraio 2026</p>
<h2>1. Titolare del trattamento</h2>
<p>Il titolare del trattamento dei dati è il gestore della piattaforma dgray.io con sede in Svizzera.</p>
<p>Il titolare del trattamento dei dati è il gestore della piattaforma kashilo.com con sede in Svizzera.</p>
<h2>2. Principio</h2>
<p>La piattaforma è stata progettata secondo il principio della minimizzazione dei dati.</p>
@@ -220,10 +220,10 @@ class PagePrivacy extends HTMLElement {
`,
es: /* html */`
<h1>Política de Privacidad</h1>
<p class="legal-meta">dgray.io — Mercado anónimo | Actualización: febrero 2026</p>
<p class="legal-meta">kashilo.com — Mercado anónimo | Actualización: febrero 2026</p>
<h2>1. Responsable del tratamiento</h2>
<p>El responsable del tratamiento de datos es el operador de la plataforma dgray.io con sede en Suiza.</p>
<p>El responsable del tratamiento de datos es el operador de la plataforma kashilo.com con sede en Suiza.</p>
<h2>2. Principio</h2>
<p>La plataforma fue diseñada según el principio de minimización de datos.</p>
@@ -271,10 +271,10 @@ class PagePrivacy extends HTMLElement {
`,
pt: /* html */`
<h1>Política de Privacidade</h1>
<p class="legal-meta">dgray.io — Mercado anônimo | Atualização: fevereiro 2026</p>
<p class="legal-meta">kashilo.com — Mercado anônimo | Atualização: fevereiro 2026</p>
<h2>1. Responsável pelo tratamento</h2>
<p>O responsável pelo tratamento de dados é o operador da plataforma dgray.io com sede na Suíça.</p>
<p>O responsável pelo tratamento de dados é o operador da plataforma kashilo.com com sede na Suíça.</p>
<h2>2. Princípio</h2>
<p>A plataforma foi projetada segundo o princípio da minimização de dados.</p>
@@ -322,10 +322,10 @@ class PagePrivacy extends HTMLElement {
`,
ru: /* html */`
<h1>Политика конфиденциальности</h1>
<p class="legal-meta">dgray.io — Анонимный маркетплейс | Обновлено: февраль 2026</p>
<p class="legal-meta">kashilo.com — Анонимный маркетплейс | Обновлено: февраль 2026</p>
<h2>1. Ответственный за обработку данных</h2>
<p>Ответственным за обработку данных является оператор платформы dgray.io с местонахождением в Швейцарии.</p>
<p>Ответственным за обработку данных является оператор платформы kashilo.com с местонахождением в Швейцарии.</p>
<h2>2. Принцип</h2>
<p>Платформа разработана по принципу минимизации данных.</p>

View File

@@ -146,11 +146,11 @@ class PageSettings extends HTMLElement {
}
getCurrentCurrency() {
return localStorage.getItem('dgray_currency') || 'USD'
return localStorage.getItem('kashilo_currency') || 'USD'
}
async setCurrency(currency) {
localStorage.setItem('dgray_currency', currency)
localStorage.setItem('kashilo_currency', currency)
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
// Save to user profile if logged in
@@ -323,7 +323,7 @@ class PageSettings extends HTMLElement {
<a href="#/privacy">${t('footer.privacy')}</a>
<a href="#/terms">${t('footer.terms')}</a>
</div>
<p class="version">dgray.io v1.0.0</p>
<p class="version">kashilo.com v1.0.0</p>
</section>
</div>
</div>

View File

@@ -40,10 +40,10 @@ class PageTerms extends HTMLElement {
getContentDE() {
return /* html */`
<h1>Allgemeine Geschäftsbedingungen (AGB)</h1>
<p class="legal-meta">dgray.io — Anonymer Marktplatz | Stand: Februar 2026</p>
<p class="legal-meta">kashilo.com — Anonymer Marktplatz | Stand: Februar 2026</p>
<h2>1. Geltungsbereich</h2>
<p>1.1 Diese AGB regeln die Nutzung der Plattform dgray.io.</p>
<p>1.1 Diese AGB regeln die Nutzung der Plattform kashilo.com.</p>
<p>1.2 Die Plattform wird betrieben von einer natürlichen Person mit Sitz in der Schweiz.</p>
<p>1.3 Mit der Nutzung der Plattform erklärt sich die nutzende Person mit diesen AGB einverstanden.</p>
@@ -114,10 +114,10 @@ class PageTerms extends HTMLElement {
getContentEN() {
return /* html */`
<h1>Terms of Service</h1>
<p class="legal-meta">dgray.io — Anonymous Marketplace | Last updated: February 2026</p>
<p class="legal-meta">kashilo.com — Anonymous Marketplace | Last updated: February 2026</p>
<h2>1. Scope</h2>
<p>1.1 These Terms of Service govern the use of the platform dgray.io.</p>
<p>1.1 These Terms of Service govern the use of the platform kashilo.com.</p>
<p>1.2 The platform is operated by a natural person based in Switzerland.</p>
<p>1.3 By using the platform, the user agrees to these terms.</p>
@@ -188,10 +188,10 @@ class PageTerms extends HTMLElement {
getContentFR() {
return /* html */`
<h1>Conditions Générales d'Utilisation (CGU)</h1>
<p class="legal-meta">dgray.io — Marché anonyme | Mise à jour : février 2026</p>
<p class="legal-meta">kashilo.com — Marché anonyme | Mise à jour : février 2026</p>
<h2>1. Champ d'application</h2>
<p>1.1 Les présentes CGU régissent l'utilisation de la plateforme dgray.io.</p>
<p>1.1 Les présentes CGU régissent l'utilisation de la plateforme kashilo.com.</p>
<p>1.2 La plateforme est exploitée par une personne physique domiciliée en Suisse.</p>
<p>1.3 En utilisant la plateforme, l'utilisateur accepte les présentes CGU.</p>
@@ -262,10 +262,10 @@ class PageTerms extends HTMLElement {
getContentIT() {
return /* html */`
<h1>Condizioni generali di utilizzo (CGU)</h1>
<p class="legal-meta">dgray.io — Mercato anonimo | Aggiornamento: febbraio 2026</p>
<p class="legal-meta">kashilo.com — Mercato anonimo | Aggiornamento: febbraio 2026</p>
<h2>1. Campo di applicazione</h2>
<p>1.1 Le presenti CGU disciplinano l'utilizzo della piattaforma dgray.io.</p>
<p>1.1 Le presenti CGU disciplinano l'utilizzo della piattaforma kashilo.com.</p>
<p>1.2 La piattaforma è gestita da una persona fisica con sede in Svizzera.</p>
<p>1.3 Utilizzando la piattaforma, l'utente accetta le presenti CGU.</p>
@@ -336,10 +336,10 @@ class PageTerms extends HTMLElement {
getContentES() {
return /* html */`
<h1>Condiciones generales de uso (CGU)</h1>
<p class="legal-meta">dgray.io — Mercado anónimo | Actualización: febrero 2026</p>
<p class="legal-meta">kashilo.com — Mercado anónimo | Actualización: febrero 2026</p>
<h2>1. Ámbito de aplicación</h2>
<p>1.1 Las presentes CGU regulan el uso de la plataforma dgray.io.</p>
<p>1.1 Las presentes CGU regulan el uso de la plataforma kashilo.com.</p>
<p>1.2 La plataforma es operada por una persona física con sede en Suiza.</p>
<p>1.3 Al utilizar la plataforma, el usuario acepta las presentes CGU.</p>
@@ -410,10 +410,10 @@ class PageTerms extends HTMLElement {
getContentPT() {
return /* html */`
<h1>Termos de Uso</h1>
<p class="legal-meta">dgray.io — Mercado anônimo | Atualização: fevereiro 2026</p>
<p class="legal-meta">kashilo.com — Mercado anônimo | Atualização: fevereiro 2026</p>
<h2>1. Âmbito de aplicação</h2>
<p>1.1 Estes Termos de Uso regulam a utilização da plataforma dgray.io.</p>
<p>1.1 Estes Termos de Uso regulam a utilização da plataforma kashilo.com.</p>
<p>1.2 A plataforma é operada por uma pessoa física com sede na Suíça.</p>
<p>1.3 Ao utilizar a plataforma, o usuário concorda com estes Termos de Uso.</p>
@@ -484,10 +484,10 @@ class PageTerms extends HTMLElement {
getContentRU() {
return /* html */`
<h1>Условия использования</h1>
<p class="legal-meta">dgray.io — Анонимный маркетплейс | Обновлено: февраль 2026</p>
<p class="legal-meta">kashilo.com — Анонимный маркетплейс | Обновлено: февраль 2026</p>
<h2>1. Область применения</h2>
<p>1.1 Настоящие Условия использования регулируют пользование платформой dgray.io.</p>
<p>1.1 Настоящие Условия использования регулируют пользование платформой kashilo.com.</p>
<p>1.2 Платформа управляется физическим лицом с местонахождением в Швейцарии.</p>
<p>1.3 Используя платформу, пользователь соглашается с настоящими Условиями использования.</p>

View File

@@ -11,14 +11,14 @@ import { setPersist, getPersist } from './directus/client.js'
import { cryptoService } from './crypto.js'
import { i18n } from '../i18n.js'
const AUTH_DOMAIN = 'dgray.io'
const AUTH_DOMAIN = 'kashilo.com'
class AuthService {
constructor() {
this.currentUser = null
this.listeners = new Set()
this.hashCache = new Map()
if (localStorage.getItem('dgray_remember') === '1') {
if (localStorage.getItem('kashilo_remember') === '1') {
setPersist(true)
}
}
@@ -142,7 +142,7 @@ class AuthService {
this.currentUser = null
this.clearStoredUuid()
localStorage.removeItem('dgray_remember')
localStorage.removeItem('kashilo_remember')
setPersist(false)
cryptoService.lock()
this.resetPreferencesToDefaults()
@@ -159,7 +159,7 @@ class AuthService {
const keysToRemove = []
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i)
if (key && key.startsWith('dgray_')) keysToRemove.push(key)
if (key && key.startsWith('kashilo_')) keysToRemove.push(key)
}
keysToRemove.forEach(k => localStorage.removeItem(k))
@@ -169,7 +169,7 @@ class AuthService {
for (let i = sessionStorage.length - 1; i >= 0; i--) {
const key = sessionStorage.key(i)
if (key && key.startsWith('dgray_')) sessionStorage.removeItem(key)
if (key && key.startsWith('kashilo_')) sessionStorage.removeItem(key)
}
}
@@ -180,7 +180,7 @@ class AuthService {
const defaultCurrency = 'USD'
const defaultLocale = 'en'
localStorage.setItem('dgray_currency', defaultCurrency)
localStorage.setItem('kashilo_currency', defaultCurrency)
localStorage.setItem('locale', defaultLocale)
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency: defaultCurrency } }))
@@ -223,7 +223,7 @@ class AuthService {
if (this.currentUser.preferred_currency) {
const currency = this.currentUser.preferred_currency
localStorage.setItem('dgray_currency', currency)
localStorage.setItem('kashilo_currency', currency)
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
}
if (this.currentUser.preferred_locale) {
@@ -261,7 +261,7 @@ class AuthService {
*/
storeUuid(uuid) {
const storage = getPersist() ? localStorage : sessionStorage
storage.setItem('dgray_uuid', uuid)
storage.setItem('kashilo_uuid', uuid)
}
/**
@@ -269,28 +269,28 @@ class AuthService {
* @returns {string|null}
*/
getStoredUuid() {
return sessionStorage.getItem('dgray_uuid') || localStorage.getItem('dgray_uuid')
return sessionStorage.getItem('kashilo_uuid') || localStorage.getItem('kashilo_uuid')
}
/**
* Clears stored UUID
*/
clearStoredUuid() {
sessionStorage.removeItem('dgray_uuid')
localStorage.removeItem('dgray_uuid')
sessionStorage.removeItem('kashilo_uuid')
localStorage.removeItem('kashilo_uuid')
}
setRememberMe(value) {
setPersist(value)
if (value) {
localStorage.setItem('dgray_remember', '1')
localStorage.setItem('kashilo_remember', '1')
} else {
localStorage.removeItem('dgray_remember')
localStorage.removeItem('kashilo_remember')
}
}
getRememberMe() {
return localStorage.getItem('dgray_remember') === '1'
return localStorage.getItem('kashilo_remember') === '1'
}
/**

View File

@@ -1,6 +1,6 @@
import { i18n } from '../i18n.js'
const POW_SERVER = 'https://pow.dgray.io'
const POW_SERVER = 'https://pow.kashilo.com'
let modalScriptLoaded = false
let modalScriptLoading = null
@@ -131,7 +131,7 @@ export async function pollUntilDone(invoiceId, options = {}) {
*/
export function getPendingInvoice(listingId) {
try {
const data = localStorage.getItem(`dgray_invoice_${listingId}`)
const data = localStorage.getItem(`kashilo_invoice_${listingId}`)
return data ? JSON.parse(data) : null
} catch (e) {
return null
@@ -145,7 +145,7 @@ export function getPendingInvoice(listingId) {
*/
export function savePendingInvoice(listingId, invoiceId) {
try {
localStorage.setItem(`dgray_invoice_${listingId}`, JSON.stringify({
localStorage.setItem(`kashilo_invoice_${listingId}`, JSON.stringify({
invoiceId,
createdAt: Date.now()
}))
@@ -159,7 +159,7 @@ export function savePendingInvoice(listingId, invoiceId) {
* @param {string} listingId
*/
export function clearPendingInvoice(listingId) {
localStorage.removeItem(`dgray_invoice_${listingId}`)
localStorage.removeItem(`kashilo_invoice_${listingId}`)
}
export default {

View File

@@ -10,8 +10,8 @@ class CategoriesService {
this.cache = null
this.cacheTimestamp = 0
this.cacheTimeout = 24 * 60 * 60 * 1000 // 24 hours
this.storageKey = 'dgray_categories'
this.storageTimestampKey = 'dgray_categories_ts'
this.storageKey = 'kashilo_categories'
this.storageTimestampKey = 'kashilo_categories_ts'
this._pending = null
this._loadFromStorage()
}

View File

@@ -6,9 +6,9 @@
* derived from the user's UUID via PBKDF2.
*/
const STORAGE_KEY = 'dgray_keypair'
const SALT_KEY = 'dgray_keypair_salt'
const LISTING_KEYS_STORAGE = 'dgray_listing_keys'
const STORAGE_KEY = 'kashilo_keypair'
const SALT_KEY = 'kashilo_keypair_salt'
const LISTING_KEYS_STORAGE = 'kashilo_listing_keys'
class CryptoService {
constructor() {

View File

@@ -195,7 +195,7 @@ export function convertFiat(amount, fromCurrency, toCurrency, rates) {
* @returns {string} Currency code (default: 'USD')
*/
export function getDisplayCurrency() {
return localStorage.getItem('dgray_currency') || 'USD'
return localStorage.getItem('kashilo_currency') || 'USD'
}
/**

View File

@@ -1,5 +1,5 @@
/**
* Directus API Service for dgray.io — Facade
* Directus API Service for kashilo.com — Facade
* Re-exports modular sub-services as a single backward-compatible singleton.
* @module services/directus
*/

View File

@@ -1,4 +1,4 @@
const DIRECTUS_URL = 'https://api.dgray.io'
const DIRECTUS_URL = 'https://api.kashilo.com'
let _persist = false
@@ -51,14 +51,14 @@ class DirectusClient {
// ── Token Management ──
loadTokens() {
const stored = sessionStorage.getItem('dgray_auth') || localStorage.getItem('dgray_auth')
const stored = sessionStorage.getItem('kashilo_auth') || localStorage.getItem('kashilo_auth')
if (stored) {
try {
const { accessToken, refreshToken, expiry } = JSON.parse(stored)
this.accessToken = accessToken
this.refreshToken = refreshToken
this.tokenExpiry = expiry
if (localStorage.getItem('dgray_auth')) {
if (localStorage.getItem('kashilo_auth')) {
_persist = true
}
this.scheduleTokenRefresh()
@@ -73,7 +73,7 @@ class DirectusClient {
this.refreshToken = refreshToken
this.tokenExpiry = Date.now() + (expiresIn * 1000)
_storage().setItem('dgray_auth', JSON.stringify({
_storage().setItem('kashilo_auth', JSON.stringify({
accessToken: this.accessToken,
refreshToken: this.refreshToken,
expiry: this.tokenExpiry
@@ -86,8 +86,8 @@ class DirectusClient {
this.accessToken = null
this.refreshToken = null
this.tokenExpiry = null
sessionStorage.removeItem('dgray_auth')
localStorage.removeItem('dgray_auth')
sessionStorage.removeItem('kashilo_auth')
localStorage.removeItem('kashilo_auth')
if (this.refreshTimeout) {
clearTimeout(this.refreshTimeout)

View File

@@ -1,7 +1,7 @@
import { directus } from './directus.js'
import { auth } from './auth.js'
const ANON_KEY = 'dgray_favorites'
const ANON_KEY = 'kashilo_favorites'
class FavoritesService {
constructor() {

View File

@@ -3,7 +3,7 @@
* Stores seller contact keys on first use, warns on key changes
*/
const PINNED_KEYS_STORAGE = 'dgray_pinned_keys'
const PINNED_KEYS_STORAGE = 'kashilo_pinned_keys'
class KeyPinningService {
constructor() {

View File

@@ -2,11 +2,11 @@
// Client must find nonce where SHA256(challenge + nonce) has N leading zeros
// Server-first: tries /pow/challenge endpoint, falls back to local generation
const POW_SERVER = 'https://pow.dgray.io'
const POW_SERVER = 'https://pow.kashilo.com'
const DIFFICULTY = 4
const SERVER_TIMEOUT_MS = 1500
const LOCAL_HMAC_KEY = 'dgray-pow-local-v1'
const LOCAL_HMAC_KEY = 'kashilo-pow-local-v1'
async function hmacSign(message) {
const enc = new TextEncoder()

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Anonyme Kleinanzeigen",
"title": "kashilo.com Anonyme Kleinanzeigen",
"description": "Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Impressum"
},
"home": {
"title": "Willkommen bei dgray.io",
"title": "Willkommen bei kashilo.com",
"subtitle": "Finde tolle Angebote in deiner Nähe oder verkaufe, was du nicht mehr brauchst.",
"browseListings": "Anzeigen durchsuchen",
"createListing": "Anzeige erstellen",

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Private Classifieds",
"title": "kashilo.com Private Classifieds",
"description": "Buy and sell without an account, without email. Pay with Monero. End-to-end encrypted chat."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Legal Notice"
},
"home": {
"title": "Welcome to dgray.io",
"title": "Welcome to kashilo.com",
"subtitle": "Find great deals near you or sell what you no longer need.",
"browseListings": "Browse Listings",
"createListing": "Create Listing",

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Clasificados anónimos",
"title": "kashilo.com Clasificados anónimos",
"description": "Compra y vende sin cuenta, sin email. Pago con Monero. Chat cifrado de extremo a extremo."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Aviso legal"
},
"home": {
"title": "Bienvenido a dgray.io",
"title": "Bienvenido a kashilo.com",
"subtitle": "Encuentra grandes ofertas cerca de ti o vende lo que ya no necesitas.",
"browseListings": "Explorar anuncios",
"createListing": "Crear anuncio",

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Petites annonces anonymes",
"title": "kashilo.com Petites annonces anonymes",
"description": "Achetez et vendez sans compte, sans e-mail. Paiement en Monero. Chat chiffré de bout en bout."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Mentions légales"
},
"home": {
"title": "Bienvenue sur dgray.io",
"title": "Bienvenue sur kashilo.com",
"subtitle": "Trouvez de bonnes affaires près de chez vous ou vendez ce dont vous n'avez plus besoin.",
"browseListings": "Parcourir les annonces",
"createListing": "Créer une annonce",

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Annunci anonimi",
"title": "kashilo.com Annunci anonimi",
"description": "Compra e vendi senza account, senza email. Pagamento in Monero. Chat crittografata end-to-end."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Avviso legale"
},
"home": {
"title": "Benvenuto su dgray.io",
"title": "Benvenuto su kashilo.com",
"subtitle": "Trova ottime offerte vicino a te o vendi ciò che non ti serve più.",
"browseListings": "Sfoglia annunci",
"createListing": "Crea annuncio",

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Classificados anônimos",
"title": "kashilo.com Classificados anônimos",
"description": "Compre e venda sem conta, sem email. Pagamento com Monero. Chat criptografado ponta a ponta."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Aviso legal"
},
"home": {
"title": "Bem-vindo ao dgray.io",
"title": "Bem-vindo ao kashilo.com",
"subtitle": "Encontre boas ofertas perto de você ou venda o que não precisa mais.",
"browseListings": "Ver Anúncios",
"createListing": "Criar Anúncio",

View File

@@ -1,6 +1,6 @@
{
"meta": {
"title": "dgray.io Анонимные объявления",
"title": "kashilo.com Анонимные объявления",
"description": "Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата."
},
"header": {
@@ -19,7 +19,7 @@
"imprint": "Правовая информация"
},
"home": {
"title": "Добро пожаловать на dgray.io",
"title": "Добро пожаловать на kashilo.com",
"subtitle": "Находите выгодные предложения рядом или продавайте ненужное.",
"browseListings": "Смотреть объявления",
"createListing": "Создать объявление",

View File

@@ -1,6 +1,6 @@
{
"name": "dgray.io - marketplace",
"short_name": "dgray.io",
"name": "kashilo.com - marketplace",
"short_name": "kashilo.com",
"description": "Anonymous marketplace with Monero payment",
"start_url": "/",
"display": "standalone",

View File

@@ -1,4 +1,4 @@
const CACHE_NAME = 'dgray-v51';
const CACHE_NAME = 'kashilo-v51';
const STATIC_ASSETS = [
'/',
'/index.html',
@@ -108,7 +108,7 @@ self.addEventListener('fetch', (event) => {
if (request.method !== 'GET') return;
// API calls: Network First (external API domain)
if (url.hostname === 'api.dgray.io') {
if (url.hostname === 'api.kashilo.com') {
event.respondWith(networkFirst(request));
return;
}

View File

@@ -136,8 +136,8 @@ describe('DirectusClient token management', () => {
// Cleanup
client.clearTokens()
sessionStorage.removeItem('dgray_auth')
localStorage.removeItem('dgray_auth')
sessionStorage.removeItem('kashilo_auth')
localStorage.removeItem('kashilo_auth')
})
test('isAuthenticated returns true with valid token', () => {
@@ -145,8 +145,8 @@ describe('DirectusClient token management', () => {
assertTrue(client.isAuthenticated())
client.clearTokens()
sessionStorage.removeItem('dgray_auth')
localStorage.removeItem('dgray_auth')
sessionStorage.removeItem('kashilo_auth')
localStorage.removeItem('kashilo_auth')
})
test('isAuthenticated returns false when token expired', () => {
@@ -163,22 +163,22 @@ describe('DirectusClient token management', () => {
refreshToken: 'stored-refresh',
expiry: Date.now() + 600000
})
sessionStorage.setItem('dgray_auth', authData)
sessionStorage.setItem('kashilo_auth', authData)
client.loadTokens()
assertEquals(client.accessToken, 'stored-access')
assertEquals(client.refreshToken, 'stored-refresh')
client.clearTokens()
sessionStorage.removeItem('dgray_auth')
sessionStorage.removeItem('kashilo_auth')
})
test('loadTokens clears on invalid JSON', () => {
sessionStorage.setItem('dgray_auth', 'not-json')
sessionStorage.setItem('kashilo_auth', 'not-json')
client.loadTokens()
assertEquals(client.accessToken, null)
sessionStorage.removeItem('dgray_auth')
sessionStorage.removeItem('kashilo_auth')
})
})

View File

@@ -26,8 +26,8 @@ describe('CryptoService', () => {
})
asyncTest('unlock generates keypair and stores encrypted', async () => {
localStorage.removeItem('dgray_keypair')
localStorage.removeItem('dgray_keypair_salt')
localStorage.removeItem('kashilo_keypair')
localStorage.removeItem('kashilo_keypair_salt')
await cryptoService.unlock(TEST_UUID)
@@ -35,7 +35,7 @@ describe('CryptoService', () => {
assertTrue(cryptoService.getPublicKey() !== null)
assertTrue(cryptoService.getPublicKey().length > 10)
const stored = JSON.parse(localStorage.getItem('dgray_keypair'))
const stored = JSON.parse(localStorage.getItem('kashilo_keypair'))
assertTrue(stored.ct !== undefined, 'stored keypair should be encrypted (has ct)')
assertTrue(stored.iv !== undefined, 'stored keypair should be encrypted (has iv)')
assertFalse(stored.publicKey !== undefined, 'stored keypair should NOT have plaintext publicKey')
@@ -77,7 +77,7 @@ describe('CryptoService', () => {
cryptoService.lock()
assertEquals(cryptoService.keyPair, null)
assertTrue(localStorage.getItem('dgray_keypair') !== null)
assertTrue(localStorage.getItem('kashilo_keypair') !== null)
})
asyncTest('destroyKeyPair clears memory and storage', async () => {
@@ -85,8 +85,8 @@ describe('CryptoService', () => {
cryptoService.destroyKeyPair()
assertEquals(cryptoService.keyPair, null)
assertEquals(localStorage.getItem('dgray_keypair'), null)
assertEquals(localStorage.getItem('dgray_keypair_salt'), null)
assertEquals(localStorage.getItem('kashilo_keypair'), null)
assertEquals(localStorage.getItem('kashilo_keypair_salt'), null)
})
asyncTest('migrates plaintext keypair to encrypted on unlock', async () => {
@@ -96,14 +96,14 @@ describe('CryptoService', () => {
publicKey: cryptoService.naclUtil.encodeBase64(kp.publicKey),
secretKey: cryptoService.naclUtil.encodeBase64(kp.secretKey)
}
localStorage.setItem('dgray_keypair', JSON.stringify(plaintext))
localStorage.removeItem('dgray_keypair_salt')
localStorage.setItem('kashilo_keypair', JSON.stringify(plaintext))
localStorage.removeItem('kashilo_keypair_salt')
await cryptoService.unlock(TEST_UUID)
assertEquals(cryptoService.getPublicKey(), plaintext.publicKey)
const stored = JSON.parse(localStorage.getItem('dgray_keypair'))
const stored = JSON.parse(localStorage.getItem('kashilo_keypair'))
assertTrue(stored.ct !== undefined, 'should be migrated to encrypted format')
assertTrue(stored.iv !== undefined)
})
@@ -255,7 +255,7 @@ describe('ConversationsService.hashPublicKey', () => {
describe('Per-listing keypair management', () => {
asyncTest('generateListingKeyPair creates and stores keypair', async () => {
localStorage.removeItem('dgray_listing_keys')
localStorage.removeItem('kashilo_listing_keys')
await cryptoService.unlock(TEST_UUID)
const publicKey = await cryptoService.generateListingKeyPair('test-listing-1')
@@ -326,7 +326,7 @@ describe('Per-listing keypair management', () => {
await cryptoService.generateListingKeyPair('temp-listing')
cryptoService.destroyKeyPair()
assertEquals(localStorage.getItem('dgray_listing_keys'), null)
assertEquals(localStorage.getItem('kashilo_listing_keys'), null)
})
})

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>dgray.io - Tests</title>
<title>kashilo.com - Tests</title>
<style>
:root {
--color-bg: #1a1a1a;
@@ -88,7 +88,7 @@
</head>
<body>
<div id="results">
<h1>🧪 dgray.io Test Suite</h1>
<h1>🧪 kashilo.com Test Suite</h1>
<p class="loading">Running tests...</p>
</div>
@@ -118,7 +118,7 @@
renderResults(container)
} catch (error) {
container.innerHTML = `
<h1>🧪 dgray.io Test Suite</h1>
<h1>🧪 kashilo.com Test Suite</h1>
<p style="color: var(--color-failed)">
Error loading tests: ${error.message}
</p>

View File

@@ -82,7 +82,7 @@ describe('getFileUrl', () => {
test('builds basic URL without options', () => {
const url = getFileUrl('abc-123')
assertEquals(url, 'https://api.dgray.io/assets/abc-123')
assertEquals(url, 'https://api.kashilo.com/assets/abc-123')
})
test('appends width parameter', () => {