refactor: rename project from dgray.io to kashilo.com
This commit is contained in:
14
AGENTS.md
14
AGENTS.md
@@ -4,7 +4,7 @@ Dieses Dokument hilft AI-Assistenten (Amp, Copilot, etc.) das Projekt zu versteh
|
|||||||
|
|
||||||
## Projekt-Überblick
|
## 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)
|
- **Status**: Active Development (Frontend + Directus Backend)
|
||||||
- **Ziel**: Anonyme, dezentrale Marktplatz-Alternative
|
- **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`) |
|
| Routing | Hash-basierter Client-Side Router (`js/router.js`) |
|
||||||
| i18n | Custom System (`js/i18n.js`), JSON-Dateien in `/locales/` |
|
| i18n | Custom System (`js/i18n.js`), JSON-Dateien in `/locales/` |
|
||||||
| Theming | CSS Variables, Dark/Light Mode |
|
| Theming | CSS Variables, Dark/Light Mode |
|
||||||
| Backend | Directus (`api.dgray.io`) |
|
| Backend | Directus (`api.kashilo.com`) |
|
||||||
| Auth | UUID-basiert, anonym (`js/services/auth.js`) |
|
| Auth | UUID-basiert, anonym (`js/services/auth.js`) |
|
||||||
| E2E Crypto | TweetNaCl (self-hosted in `js/vendor/`), `box.before` + `secretbox` |
|
| 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
|
## Häufige Befehle
|
||||||
|
|
||||||
@@ -90,8 +90,8 @@ docs/
|
|||||||
├── MONETIZATION.md # Monetarisierung & Anti-Abuse
|
├── MONETIZATION.md # Monetarisierung & Anti-Abuse
|
||||||
├── LAUNCH-PLAN.md # Release-Phasen, Pricing, Checkliste
|
├── LAUNCH-PLAN.md # Release-Phasen, Pricing, Checkliste
|
||||||
├── REPUTATION.md # Reputation-System (Konzept, Directus-Anleitung)
|
├── REPUTATION.md # Reputation-System (Konzept, Directus-Anleitung)
|
||||||
├── pow-server/ # PHP PoW-Captcha Server (pow.dgray.io)
|
├── pow-server/ # PHP PoW-Captcha Server (pow.kashilo.com)
|
||||||
└── og-proxy.php # Open Graph Meta-Tag Proxy (pow.dgray.io)
|
└── og-proxy.php # Open Graph Meta-Tag Proxy (pow.kashilo.com)
|
||||||
|
|
||||||
css/
|
css/
|
||||||
├── fonts.css # @font-face Definitionen (Inter, Space Grotesk)
|
├── fonts.css # @font-face Definitionen (Inter, Space Grotesk)
|
||||||
@@ -163,10 +163,10 @@ locales/
|
|||||||
1. ~~Seiten für Profil-Dropdown~~ ✅ Fertig
|
1. ~~Seiten für Profil-Dropdown~~ ✅ Fertig
|
||||||
2. ~~Suchseite mit Filtern~~ ✅ Merged in `page-home.js`
|
2. ~~Suchseite mit Filtern~~ ✅ Merged in `page-home.js`
|
||||||
3. ~~Listings bearbeiten~~ ✅ Edit-Modus via `#/edit/:id`
|
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/`
|
5. ~~TweetNaCl self-hosted~~ ✅ In `js/vendor/`
|
||||||
6. ~~Chat-Crypto fix~~ ✅ Per-listing E2E Keys, TOFU Key-Pinning, kein Pending-Flow mehr
|
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
|
8. ~~Favoriten Directus Sync~~ ✅ FavoritesService mit Union-Merge bei Login
|
||||||
9. ~~Expired Listings~~ ✅ Directus Flow (alle 15 Min), Status-Badges auf Cards
|
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`)
|
10. ~~Reputation-System~~ ✅ `reputation.js` Service, Deals/Ratings Collections, Chat-Widget Deal-Bestätigung + Sterne-Bewertung, Seller-Card Badges (siehe `docs/REPUTATION.md`)
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -1,10 +1,10 @@
|
|||||||
# dgray.io
|
# kashilo.com
|
||||||
|
|
||||||
Eine anonyme, dezentrale Kleinanzeigen-Plattform mit Monero-Bezahlung.
|
Eine anonyme, dezentrale Kleinanzeigen-Plattform mit Monero-Bezahlung.
|
||||||
|
|
||||||
## 🎯 Vision
|
## 🎯 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
|
- **Anonymität**: Nutzung ohne Account möglich
|
||||||
- **Direkte Zahlung**: Peer-to-Peer via Monero, keine Zahlungsvermittlung
|
- **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
|
- Custom Extensions für XMR-Integration
|
||||||
|
|
||||||
### Services
|
### Services
|
||||||
- **Directus** Backend: `api.dgray.io` (Docker)
|
- **Directus** Backend: `api.kashilo.com` (Docker)
|
||||||
- **PoW Captcha + Payment Proxy**: `pow.dgray.io` (PHP, HMAC-signierte Challenges, BTCPay Proxy + Webhook, OG Meta Proxy)
|
- **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)
|
- **BTCPay Server**: `pay.xmr.rocks` (Monero-Zahlungen, Trocador-Plugin)
|
||||||
- **TweetNaCl**: Self-hosted in `js/vendor/` (E2E-Verschlüsselung)
|
- **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
|
```bash
|
||||||
# Einmalig: SSH-User und Pfad anpassen
|
# 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:
|
# Oder Defaults im Script setzen und einfach:
|
||||||
./deploy.sh
|
./deploy.sh
|
||||||
@@ -152,7 +152,7 @@ Die Tests laufen im Browser und nutzen einen minimalen Test-Runner ohne externe
|
|||||||
### Projektstruktur
|
### Projektstruktur
|
||||||
|
|
||||||
```
|
```
|
||||||
dgray/
|
kashilo/
|
||||||
├── index.html # Entry Point
|
├── index.html # Entry Point
|
||||||
├── manifest.json # PWA Manifest
|
├── manifest.json # PWA Manifest
|
||||||
├── service-worker.js # Offline-Support
|
├── service-worker.js # Offline-Support
|
||||||
@@ -222,7 +222,7 @@ dgray/
|
|||||||
- [ ] Responsive Optimierungen
|
- [ ] Responsive Optimierungen
|
||||||
|
|
||||||
### Phase 2: Backend-Integration ⬅️ **Aktuell**
|
### Phase 2: Backend-Integration ⬅️ **Aktuell**
|
||||||
- [x] Directus aufsetzen (`api.dgray.io`)
|
- [x] Directus aufsetzen (`api.kashilo.com`)
|
||||||
- [x] Listings-Collection (CRUD)
|
- [x] Listings-Collection (CRUD)
|
||||||
- [x] Categories mit Übersetzungen
|
- [x] Categories mit Übersetzungen
|
||||||
- [x] User-Auth (UUID + SHA-256 Hash, anonym)
|
- [x] User-Auth (UUID + SHA-256 Hash, anonym)
|
||||||
@@ -237,7 +237,7 @@ dgray/
|
|||||||
- [x] Conversations/Messages Services
|
- [x] Conversations/Messages Services
|
||||||
- [x] Merkliste (Favoriten-Seite)
|
- [x] Merkliste (Favoriten-Seite)
|
||||||
- [x] Favoriten Directus-Sync (Union-Merge bei Login, localStorage-Fallback)
|
- [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] TweetNaCl self-hosted (kein CDN)
|
||||||
- [x] In-App Benachrichtigungen (Notifications-Service, Glocke mit Badge)
|
- [x] In-App Benachrichtigungen (Notifications-Service, Glocke mit Badge)
|
||||||
- [x] Open Graph & X Card Meta-Tags (dynamisch pro Listing)
|
- [x] Open Graph & X Card Meta-Tags (dynamisch pro Listing)
|
||||||
@@ -246,7 +246,7 @@ dgray/
|
|||||||
### Phase 4: Payments
|
### Phase 4: Payments
|
||||||
- [x] XMR-Kursabfrage API (CoinGecko)
|
- [x] XMR-Kursabfrage API (CoinGecko)
|
||||||
- [x] Fiat ↔ XMR Umrechnung (Dual-Preis-Anzeige)
|
- [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] Listing-Gebühr: 1 EUR/USD/CHF/GBP (200 JPY) via Monero
|
||||||
- [x] Webhook für Auto-Publish nach Blockchain-Confirmation
|
- [x] Webhook für Auto-Publish nach Blockchain-Confirmation
|
||||||
- [x] Expired Listings (Directus Flow, Status-Badges auf Cards)
|
- [x] Expired Listings (Directus Flow, Status-Badges auf Cards)
|
||||||
|
|||||||
@@ -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>
|
<style>
|
||||||
.logo-text {
|
.logo-text {
|
||||||
font-family: 'Space Grotesk', system-ui, sans-serif;
|
font-family: 'Space Grotesk', system-ui, sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 24px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<text x="4" y="24" class="logo-text">
|
<text x="2" y="28" class="logo-text">
|
||||||
<tspan fill="#10B981">d</tspan><tspan fill="#AAAAAA">gray</tspan>
|
<tspan fill="#10B981">k</tspan><tspan fill="#AAAAAA">ashilo</tspan>
|
||||||
</text>
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 341 B |
@@ -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>
|
<style>
|
||||||
.logo-text {
|
.logo-text {
|
||||||
font-family: 'Space Grotesk', system-ui, sans-serif;
|
font-family: 'Space Grotesk', system-ui, sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 24px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<text x="4" y="24" class="logo-text">
|
<text x="2" y="28" class="logo-text">
|
||||||
<tspan fill="#059669">d</tspan><tspan fill="#555555">gray</tspan>
|
<tspan fill="#059669">k</tspan><tspan fill="#555555">ashilo</tspan>
|
||||||
</text>
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 341 B |
@@ -1,4 +1,4 @@
|
|||||||
# dgray.io Press Kit
|
# kashilo.com Press Kit
|
||||||
|
|
||||||
## Brand Assets
|
## Brand Assets
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
## Verwendung
|
## Verwendung
|
||||||
|
|
||||||
- Logo nicht verzerren, strecken oder recolorieren
|
- 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
|
- Bevorzugt SVG verwenden
|
||||||
- Bei dunklem Hintergrund: `logo-light` verwenden
|
- Bei dunklem Hintergrund: `logo-light` verwenden
|
||||||
- Bei hellem Hintergrund: `logo-dark` verwenden
|
- Bei hellem Hintergrund: `logo-dark` verwenden
|
||||||
@@ -43,10 +43,10 @@
|
|||||||
## Beschreibung (Copy & Paste)
|
## Beschreibung (Copy & Paste)
|
||||||
|
|
||||||
**Kurz (1 Satz):**
|
**Kurz (1 Satz):**
|
||||||
dgray.io ist ein anonymer Kleinanzeigen-Marktplatz mit Monero-Bezahlung.
|
kashilo.com ist ein anonymer Kleinanzeigen-Marktplatz mit Monero-Bezahlung.
|
||||||
|
|
||||||
**Mittel (2–3 Sätze):**
|
**Mittel (2–3 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:**
|
**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.
|
||||||
|
|||||||
2
build.py
2
build.py
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Build script for dgray.io
|
Build script for kashilo.com
|
||||||
Minifies JS and CSS files into dist/ directory.
|
Minifies JS and CSS files into dist/ directory.
|
||||||
|
|
||||||
Usage: python3 build.py
|
Usage: python3 build.py
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
:root {
|
:root {
|
||||||
/*
|
/*
|
||||||
* Monochrome Theme - dgray.io
|
* Monochrome Theme - kashilo.com
|
||||||
* Pure grayscale with neon green accent
|
* Pure grayscale with neon green accent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
10
deploy.sh
10
deploy.sh
@@ -1,8 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/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]
|
# 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:
|
# Prerequisites:
|
||||||
# - SSH key authentication configured
|
# - SSH key authentication configured
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# --- Configuration ---
|
# --- Configuration ---
|
||||||
REMOTE_USER_HOST="${1:-admin@dgray.io}"
|
REMOTE_USER_HOST="${1:-admin@kashilo.com}"
|
||||||
REMOTE_PATH="${2:-/home/admin/web/dgray.io/public_html}"
|
REMOTE_PATH="${2:-/home/admin/web/kashilo.com/public_html}"
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
DIST_DIR="$SCRIPT_DIR/dist"
|
DIST_DIR="$SCRIPT_DIR/dist"
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ python3 "$SCRIPT_DIR/build.py"
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# --- Deploy from dist/ ---
|
# --- Deploy from dist/ ---
|
||||||
echo "Deploying dgray.io"
|
echo "Deploying kashilo.com"
|
||||||
echo " From: $DIST_DIR"
|
echo " From: $DIST_DIR"
|
||||||
echo " To: $REMOTE_USER_HOST:$REMOTE_PATH"
|
echo " To: $REMOTE_USER_HOST:$REMOTE_PATH"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Directus Version:** 11.14.1
|
**Directus Version:** 11.14.1
|
||||||
**Database:** PostgreSQL
|
**Database:** PostgreSQL
|
||||||
**API Endpoint:** https://api.dgray.io
|
**API Endpoint:** https://api.kashilo.com
|
||||||
|
|
||||||
## Collections Overview
|
## Collections Overview
|
||||||
|
|
||||||
|
|||||||
@@ -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**
|
**Settings > Project Settings**
|
||||||
|
|
||||||
```
|
```
|
||||||
Project Name: dgray.io
|
Project Name: kashilo.com
|
||||||
Project URL: https://dgray.io
|
Project URL: https://kashilo.com
|
||||||
Project Color: #555555
|
Project Color: #555555
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -637,7 +637,7 @@ services:
|
|||||||
image: directus/directus:latest
|
image: directus/directus:latest
|
||||||
environment:
|
environment:
|
||||||
CORS_ENABLED: "true"
|
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_METHODS: "GET,POST,PATCH,DELETE"
|
||||||
CORS_ALLOWED_HEADERS: "Content-Type,Authorization"
|
CORS_ALLOWED_HEADERS: "Content-Type,Authorization"
|
||||||
CORS_CREDENTIALS: "true"
|
CORS_CREDENTIALS: "true"
|
||||||
@@ -655,7 +655,7 @@ services:
|
|||||||
```env
|
```env
|
||||||
# .env
|
# .env
|
||||||
CORS_ENABLED=true
|
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_METHODS=GET,POST,PATCH,DELETE
|
||||||
CORS_ALLOWED_HEADERS=Content-Type,Authorization
|
CORS_ALLOWED_HEADERS=Content-Type,Authorization
|
||||||
CORS_CREDENTIALS=true
|
CORS_CREDENTIALS=true
|
||||||
@@ -706,7 +706,7 @@ environment:
|
|||||||
STORAGE_S3_DRIVER: "s3"
|
STORAGE_S3_DRIVER: "s3"
|
||||||
STORAGE_S3_KEY: "your-access-key"
|
STORAGE_S3_KEY: "your-access-key"
|
||||||
STORAGE_S3_SECRET: "your-secret-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_REGION: "fsn1" # oder nbg1
|
||||||
STORAGE_S3_ENDPOINT: "https://fsn1.your-objectstorage.com" # oder nbg1
|
STORAGE_S3_ENDPOINT: "https://fsn1.your-objectstorage.com" # oder nbg1
|
||||||
```
|
```
|
||||||
@@ -720,7 +720,7 @@ environment:
|
|||||||
STORAGE_S3_DRIVER: "s3"
|
STORAGE_S3_DRIVER: "s3"
|
||||||
STORAGE_S3_KEY: "your-access-key"
|
STORAGE_S3_KEY: "your-access-key"
|
||||||
STORAGE_S3_SECRET: "your-secret-key"
|
STORAGE_S3_SECRET: "your-secret-key"
|
||||||
STORAGE_S3_BUCKET: "dgray-files"
|
STORAGE_S3_BUCKET: "kashilo-files"
|
||||||
STORAGE_S3_REGION: "auto"
|
STORAGE_S3_REGION: "auto"
|
||||||
STORAGE_S3_ENDPOINT: "https://xxx.r2.cloudflarestorage.com"
|
STORAGE_S3_ENDPOINT: "https://xxx.r2.cloudflarestorage.com"
|
||||||
```
|
```
|
||||||
@@ -746,7 +746,7 @@ RATE_LIMITER_POINTS=100
|
|||||||
RATE_LIMITER_DURATION=60
|
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
|
### 5.6 Währungsumrechnung & Preismodus
|
||||||
|
|
||||||
@@ -901,7 +901,7 @@ if (directus.isAuthenticated()) {
|
|||||||
|
|
||||||
## 9. Anonyme Authentifizierung (UUID-basiert)
|
## 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
|
### 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 │
|
│ f47ac10b-58cc-4372-a567-0e02b2c3d479 │
|
||||||
│ ↓ │
|
│ ↓ │
|
||||||
│ Directus erhält: │
|
│ 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 │
|
│ • Passwort: f47ac10b-58cc-4372-a567-0e02b2c3d479 │
|
||||||
│ ↓ │
|
│ ↓ │
|
||||||
│ User speichert UUID → fertig │
|
│ User speichert UUID → fertig │
|
||||||
@@ -943,7 +943,7 @@ Für maximale Privatsphäre nutzt dgray.io ein UUID-basiertes Login-System ohne
|
|||||||
// Account erstellen
|
// Account erstellen
|
||||||
async function createAnonymousAccount() {
|
async function createAnonymousAccount() {
|
||||||
const uuid = crypto.randomUUID();
|
const uuid = crypto.randomUUID();
|
||||||
const email = `${uuid}@dgray.io`;
|
const email = `${uuid}@kashilo.com`;
|
||||||
const password = uuid;
|
const password = uuid;
|
||||||
|
|
||||||
// Bei Directus registrieren
|
// Bei Directus registrieren
|
||||||
@@ -957,7 +957,7 @@ async function createAnonymousAccount() {
|
|||||||
|
|
||||||
// Login
|
// Login
|
||||||
async function login(uuid) {
|
async function login(uuid) {
|
||||||
const email = `${uuid}@dgray.io`;
|
const email = `${uuid}@kashilo.com`;
|
||||||
await directus.login(email, uuid);
|
await directus.login(email, uuid);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Killer-Features — dgray.io
|
# Killer-Features — kashilo.com
|
||||||
|
|
||||||
Differenzierung gegenüber eBay Kleinanzeigen, Tutti, XMRBazaar.
|
Differenzierung gegenüber eBay Kleinanzeigen, Tutti, XMRBazaar.
|
||||||
Drei Features, die kein Konkurrent hat.
|
Drei Features, die kein Konkurrent hat.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Launch Plan – dgray.io
|
# Launch Plan – kashilo.com
|
||||||
|
|
||||||
## Release-Phasen
|
## Release-Phasen
|
||||||
|
|
||||||
@@ -48,12 +48,12 @@ Die Validierung passiert **serverseitig** im PoW-Server (PHP), nicht im Frontend
|
|||||||
Neuer Endpoint: `POST /invite/validate`
|
Neuer Endpoint: `POST /invite/validate`
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// pow.dgray.io/invite/validate.php
|
// pow.kashilo.com/invite/validate.php
|
||||||
<?php
|
<?php
|
||||||
require __DIR__ . '/config.php';
|
require __DIR__ . '/config.php';
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
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-Methods: POST, OPTIONS');
|
||||||
header('Access-Control-Allow-Headers: Content-Type');
|
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:
|
Vor `createAccount()` den Code serverseitig validieren:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const res = await fetch('https://pow.dgray.io/invite/validate', {
|
const res = await fetch('https://pow.kashilo.com/invite/validate', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ code: inviteCode })
|
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)
|
## Meta-Tags (pro Sprache)
|
||||||
|
|
||||||
Die statischen Meta-Tags in `index.html` sind deutsch (Fallback).
|
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
|
### Umgesetzte Texte
|
||||||
|
|
||||||
**Title:** `dgray.io – [Sprache]`
|
**Title:** `kashilo.com – [Sprache]`
|
||||||
|
|
||||||
| Sprache | Title | Description |
|
| 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. |
|
| **de** | kashilo.com – 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. |
|
| **en** | kashilo.com – 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. |
|
| **fr** | kashilo.com – 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. |
|
| **it** | kashilo.com – 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. |
|
| **es** | kashilo.com – 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. |
|
| **pt** | kashilo.com – Classificados anônimos | Compre e venda sem conta, sem email. Pagamento com Monero. Chat criptografado ponta a ponta. |
|
||||||
| **ru** | dgray.io – Анонимные объявления | Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата. |
|
| **ru** | kashilo.com – Анонимные объявления | Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата. |
|
||||||
|
|
||||||
### Umsetzung
|
### Umsetzung
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ und `twitter:title/description` dynamisch bei jedem Sprachwechsel (i18n-Keys `me
|
|||||||
## Checkliste vor Alpha-Start
|
## Checkliste vor Alpha-Start
|
||||||
|
|
||||||
- [ ] Directus: Collection `invite_codes` anlegen (Schema siehe oben)
|
- [ ] 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` → `LISTING_FEE` auf 0.01 setzen
|
||||||
- [ ] PHP: `config.php` → `REQUIRE_INVITE_CODE = true`
|
- [ ] PHP: `config.php` → `REQUIRE_INVITE_CODE = true`
|
||||||
- [ ] Frontend: Invite-Code-Feld in `auth-modal.js` einbauen
|
- [ ] Frontend: Invite-Code-Feld in `auth-modal.js` einbauen
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Marketing-Strategie dgray.io
|
# Marketing-Strategie kashilo.com
|
||||||
|
|
||||||
## Positionierung
|
## Positionierung
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
### Woche 5: Name Reveal
|
### 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)
|
- Landing Page live schalten (optional, kann auch direkt die App sein)
|
||||||
- Einmalig in relevanten Subreddits posten: r/Monero, r/privacy, r/selfhosted
|
- Einmalig in relevanten Subreddits posten: r/Monero, r/privacy, r/selfhosted
|
||||||
|
|
||||||
@@ -58,10 +58,10 @@
|
|||||||
- **Ziel:** Echte Listings generieren, Feedback sammeln, Bugs finden
|
- **Ziel:** Echte Listings generieren, Feedback sammeln, Bugs finden
|
||||||
|
|
||||||
**Launch-Post auf X:**
|
**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.
|
> First 100 listings for just 0.10 EUR.
|
||||||
> No KYC. No email. No tracking. E2E encrypted chat.
|
> No KYC. No email. No tracking. E2E encrypted chat.
|
||||||
> Try it: https://dgray.io"
|
> Try it: https://kashilo.com"
|
||||||
|
|
||||||
### Weitere Launch-Kanäle
|
### Weitere Launch-Kanäle
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
- **Weekly Update** auf X: Neue Features, Stats (wenn Schwellwert erreicht)
|
- **Weekly Update** auf X: Neue Features, Stats (wenn Schwellwert erreicht)
|
||||||
- **Build in Public:** Entwicklungsfortschritte teilen
|
- **Build in Public:** Entwicklungsfortschritte teilen
|
||||||
- **User Stories:** Erfolgreiche Deals highlighten (anonym natürlich)
|
- **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
|
### Community
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
| XmrBazaar | Etabliert, 7800 User | Spam, altbackenes Design, nur EN |
|
| XmrBazaar | Etabliert, 7800 User | Spam, altbackenes Design, nur EN |
|
||||||
| Bitejo | Dezentral | Wenig Nutzer |
|
| Bitejo | Dezentral | Wenig Nutzer |
|
||||||
| MoneroMarket | Einfach | Kaum Features |
|
| MoneroMarket | Einfach | Kaum Features |
|
||||||
| **dgray.io** | Modern, lokal, E2E, PWA | Neu, noch keine User |
|
| **kashilo.com** | Modern, lokal, E2E, PWA | Neu, noch keine User |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Monetarisierung - dgray.io
|
# Monetarisierung - kashilo.com
|
||||||
|
|
||||||
## Preismodell
|
## Preismodell
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
- **Provider**: BTCpay Server (self-hosted)
|
- **Provider**: BTCpay Server (self-hosted)
|
||||||
- **URL**: https://pay.xmr.rocks/
|
- **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)
|
- **Primär**: Monero (XMR)
|
||||||
- **Alternativ**: Andere Kryptos via Trocador-Plugin (automatischer Swap zu XMR)
|
- **Alternativ**: Andere Kryptos via Trocador-Plugin (automatischer Swap zu XMR)
|
||||||
- **Preisumrechnung**: Live XMR-Kurs via Kraken API
|
- **Preisumrechnung**: Live XMR-Kurs via Kraken API
|
||||||
@@ -60,14 +60,14 @@
|
|||||||
### Flow: Draft → Processing → Published
|
### Flow: Draft → Processing → Published
|
||||||
|
|
||||||
1. User erstellt Listing → wird als `draft` mit `payment_status: unpaid` gespeichert
|
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`)
|
3. BTCPay Checkout-Modal öffnet sich im Frontend (`js/services/btcpay.js`)
|
||||||
4. Nach Zahlung:
|
4. Nach Zahlung:
|
||||||
- **Frontend**: Prüft Status via `pow.dgray.io/btcpay/status` nach Modal-Close
|
- **Frontend**: Prüft Status via `pow.kashilo.com/btcpay/status` nach Modal-Close
|
||||||
- **Webhook**: `pow.dgray.io/btcpay/webhook` empfängt BTCPay Events, setzt `status: published` + `payment_status: paid` nach 1 Confirmation
|
- **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)
|
5. Listing wird veröffentlicht (30 Tage Laufzeit, `expires_at` wird gesetzt)
|
||||||
|
|
||||||
### Endpunkte (pow.dgray.io)
|
### Endpunkte (pow.kashilo.com)
|
||||||
|
|
||||||
| Endpoint | Methode | Beschreibung |
|
| Endpoint | Methode | Beschreibung |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
@@ -81,5 +81,5 @@
|
|||||||
- [x] ~~XMR-Kurs API für Umrechnung~~ → Kraken API
|
- [x] ~~XMR-Kurs API für Umrechnung~~ → Kraken API
|
||||||
- [x] ~~Anzahl Deals für Power-User Status~~ → 5/15/50 Stufen
|
- [x] ~~Anzahl Deals für Power-User Status~~ → 5/15/50 Stufen
|
||||||
- [x] ~~Captcha-Lösung~~ → Eigenes PoW-Captcha (keine Lizenzkosten)
|
- [x] ~~Captcha-Lösung~~ → Eigenes PoW-Captcha (keine Lizenzkosten)
|
||||||
- [x] ~~Payment-Proxy~~ → `pow.dgray.io` (PHP, API-Key serverseitig)
|
- [x] ~~Payment-Proxy~~ → `pow.kashilo.com` (PHP, API-Key serverseitig)
|
||||||
- [x] ~~Webhook für Auto-Publish~~ → `btcpay-webhook.php` auf `pow.dgray.io`
|
- [x] ~~Webhook für Auto-Publish~~ → `btcpay-webhook.php` auf `pow.kashilo.com`
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Datenschutzerklärung
|
# Datenschutzerklärung
|
||||||
|
|
||||||
**dgray.io — Anonymer Marktplatz**
|
**kashilo.com — Anonymer Marktplatz**
|
||||||
Stand: Februar 2026
|
Stand: Februar 2026
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Verantwortlicher
|
## 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Reputation-System — dgray.io
|
# Reputation-System — kashilo.com
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Allgemeine Geschäftsbedingungen (AGB)
|
# Allgemeine Geschäftsbedingungen (AGB)
|
||||||
|
|
||||||
**dgray.io — Anonymer Marktplatz**
|
**kashilo.com — Anonymer Marktplatz**
|
||||||
Stand: Februar 2026
|
Stand: Februar 2026
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Geltungsbereich
|
## 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»).
|
1.2 Die Plattform wird betrieben von einer natürlichen Person mit Sitz in der Schweiz (nachfolgend «Betreiber»).
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
# This script adds it-IT, es-ES, pt-BR, ru-RU translations to all categories.
|
# 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.
|
# 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}"
|
TOKEN="${DIRECTUS_TOKEN:?Set DIRECTUS_TOKEN environment variable}"
|
||||||
|
|
||||||
add_translation() {
|
add_translation() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/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
|
# 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}"
|
TOKEN="${DIRECTUS_TOKEN:?Set DIRECTUS_TOKEN environment variable}"
|
||||||
|
|
||||||
create_category() {
|
create_category() {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# PoW Captcha & Payment Server
|
# 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
|
## 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
|
2. Dateien in das Web-Root kopieren
|
||||||
3. Secrets setzen:
|
3. Secrets setzen:
|
||||||
```bash
|
```bash
|
||||||
@@ -18,10 +18,10 @@ PHP-basierter Server für dgray.io mit Proof-of-Work Captcha und BTCPay Payment-
|
|||||||
4. Testen:
|
4. Testen:
|
||||||
```bash
|
```bash
|
||||||
# PoW Challenge
|
# PoW Challenge
|
||||||
curl https://pow.dgray.io/challenge
|
curl https://pow.kashilo.com/challenge
|
||||||
|
|
||||||
# BTCPay Invoice erstellen
|
# 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" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"listingId": "test-123", "currency": "EUR"}'
|
-d '{"listingId": "test-123", "currency": "EUR"}'
|
||||||
```
|
```
|
||||||
@@ -76,7 +76,7 @@ Response:
|
|||||||
### POST /btcpay/webhook
|
### POST /btcpay/webhook
|
||||||
Empfängt BTCPay Server Webhook-Events. Wird in BTCPay unter Store → Settings → Webhooks konfiguriert.
|
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)
|
- **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)
|
- **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
|
- **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)
|
- HMAC-SHA256 signierte Challenges (nicht fälschbar)
|
||||||
- TTL: 2 Minuten
|
- TTL: 2 Minuten
|
||||||
- CORS: nur `https://dgray.io`
|
- CORS: nur `https://kashilo.com`
|
||||||
- `hash_equals()` gegen Timing-Attacks
|
- `hash_equals()` gegen Timing-Attacks
|
||||||
- BTCPay API-Key bleibt serverseitig (nie im Frontend)
|
- BTCPay API-Key bleibt serverseitig (nie im Frontend)
|
||||||
- Gebühren serverseitig erzwungen (nicht manipulierbar)
|
- Gebühren serverseitig erzwungen (nicht manipulierbar)
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ define('BTCPAY_STORE_ID', getenv('BTCPAY_STORE_ID') ?: 'CHANGE_ME');
|
|||||||
define('BTCPAY_WEBHOOK_SECRET', getenv('BTCPAY_WEBHOOK_SECRET') ?: '');
|
define('BTCPAY_WEBHOOK_SECRET', getenv('BTCPAY_WEBHOOK_SECRET') ?: '');
|
||||||
define('LISTING_FEE', ['EUR' => 1, 'USD' => 1, 'CHF' => 1, 'GBP' => 1, 'JPY' => 200]);
|
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');
|
define('DIRECTUS_TOKEN', getenv('DIRECTUS_TOKEN') ?: 'CHANGE_ME');
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
header('Content-Type: application/json');
|
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'] ?? '';
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||||
if (in_array($origin, $allowedOrigins)) {
|
if (in_array($origin, $allowedOrigins)) {
|
||||||
header('Access-Control-Allow-Origin: ' . $origin);
|
header('Access-Control-Allow-Origin: ' . $origin);
|
||||||
} else {
|
} 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');
|
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
/**
|
/**
|
||||||
* OG Meta Tag Proxy for Social Media Crawlers
|
* 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
|
* If User-Agent matches crawler → proxy to this script
|
||||||
* Else → serve static index.html
|
* Else → serve static index.html
|
||||||
*
|
*
|
||||||
* Example Apache config (in VHost):
|
* Example Apache config (in VHost):
|
||||||
* RewriteEngine On
|
* RewriteEngine On
|
||||||
* RewriteCond %{HTTP_USER_AGENT} Twitterbot|facebookexternalhit|TelegramBot|Discordbot|Slackbot|WhatsApp [NC]
|
* 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
|
* Required modules: sudo a2enmod rewrite proxy proxy_http
|
||||||
*
|
*
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
* location /listing/ {
|
* location /listing/ {
|
||||||
* if ($http_user_agent ~* "Twitterbot|facebookexternalhit|TelegramBot|Discordbot|Slackbot|WhatsApp") {
|
* if ($http_user_agent ~* "Twitterbot|facebookexternalhit|TelegramBot|Discordbot|Slackbot|WhatsApp") {
|
||||||
* rewrite ^/listing/(.*)$ /og-proxy.php?listing=$1 break;
|
* 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'];
|
$listingId = $_GET['listing'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$siteUrl = 'https://dgray.io';
|
$siteUrl = 'https://kashilo.com';
|
||||||
$defaultTitle = 'dgray.io – Anonymous Classifieds with Monero';
|
$defaultTitle = 'kashilo.com – Anonymous Classifieds with Monero';
|
||||||
$defaultDesc = 'Buy and sell anonymously with Monero. No KYC, no email, E2E encrypted chat.';
|
$defaultDesc = 'Buy and sell anonymously with Monero. No KYC, no email, E2E encrypted chat.';
|
||||||
$defaultImage = $siteUrl . '/assets/press/og-image.png';
|
$defaultImage = $siteUrl . '/assets/press/og-image.png';
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ if ($listingId) {
|
|||||||
$listing = $data['data'] ?? null;
|
$listing = $data['data'] ?? null;
|
||||||
|
|
||||||
if ($listing) {
|
if ($listing) {
|
||||||
$title = htmlspecialchars($listing['title'] ?? '') . ' – dgray.io';
|
$title = htmlspecialchars($listing['title'] ?? '') . ' – kashilo.com';
|
||||||
$description = htmlspecialchars(mb_substr($listing['description'] ?? '', 0, 160));
|
$description = htmlspecialchars(mb_substr($listing['description'] ?? '', 0, 160));
|
||||||
$url = $siteUrl . '/#/listing/' . $listing['id'];
|
$url = $siteUrl . '/#/listing/' . $listing['id'];
|
||||||
$type = 'product';
|
$type = 'product';
|
||||||
@@ -101,7 +101,7 @@ header('Content-Type: text/html; charset=utf-8');
|
|||||||
|
|
||||||
<!-- Open Graph -->
|
<!-- Open Graph -->
|
||||||
<meta property="og:type" content="<?= $type ?>">
|
<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:title" content="<?= $title ?>">
|
||||||
<meta property="og:description" content="<?= $description ?>">
|
<meta property="og:description" content="<?= $description ?>">
|
||||||
<meta property="og:url" content="<?= $url ?>">
|
<meta property="og:url" content="<?= $url ?>">
|
||||||
|
|||||||
16
index.html
16
index.html
@@ -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="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">
|
<meta name="theme-color" content="#555555">
|
||||||
|
|
||||||
<title>dgray.io – Anonyme Kleinanzeigen</title>
|
<title>kashilo.com – Anonyme Kleinanzeigen</title>
|
||||||
|
|
||||||
<!-- Open Graph -->
|
<!-- Open Graph -->
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:site_name" content="dgray.io">
|
<meta property="og:site_name" content="kashilo.com">
|
||||||
<meta property="og:title" content="dgray.io – Anonyme Kleinanzeigen">
|
<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: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:url" content="https://kashilo.com">
|
||||||
<meta property="og:image" content="https://dgray.io/assets/press/og-image.png">
|
<meta property="og:image" content="https://kashilo.com/assets/press/og-image.png">
|
||||||
<meta property="og:image:width" content="1200">
|
<meta property="og:image:width" content="1200">
|
||||||
<meta property="og:image:height" content="630">
|
<meta property="og:image:height" content="630">
|
||||||
<meta property="og:locale" content="de_DE">
|
<meta property="og:locale" content="de_DE">
|
||||||
@@ -23,9 +23,9 @@
|
|||||||
|
|
||||||
<!-- X (Twitter) Card -->
|
<!-- X (Twitter) Card -->
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<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: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="manifest" href="manifest.json">
|
||||||
<link rel="icon" type="image/svg+xml" href="assets/icon-light.svg" media="(prefers-color-scheme: light)">
|
<link rel="icon" type="image/svg+xml" href="assets/icon-light.svg" media="(prefers-color-scheme: light)">
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
<app-footer>
|
<app-footer>
|
||||||
<div class="footer-inner container">
|
<div class="footer-inner container">
|
||||||
<p class="footer-copyright">
|
<p class="footer-copyright">
|
||||||
© 2026 dgray.io - <span data-i18n="footer.rights">Alle Rechte vorbehalten.</span>
|
© 2026 kashilo.com - <span data-i18n="footer.rights">Alle Rechte vorbehalten.</span>
|
||||||
<span class="footer-swiss">🇨🇭 Made in Switzerland</span>
|
<span class="footer-swiss">🇨🇭 Made in Switzerland</span>
|
||||||
</p>
|
</p>
|
||||||
<span class="xmr-rate" title="CoinGecko">1 XMR ≈ ...</span>
|
<span class="xmr-rate" title="CoinGecko">1 XMR ≈ ...</span>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class AppFooter extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrency() {
|
getCurrency() {
|
||||||
return localStorage.getItem('dgray_currency') || 'USD'
|
return localStorage.getItem('kashilo_currency') || 'USD'
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadXmrRates() {
|
async loadXmrRates() {
|
||||||
@@ -54,7 +54,7 @@ class AppFooter extends HTMLElement {
|
|||||||
this.innerHTML = /* html */`
|
this.innerHTML = /* html */`
|
||||||
<div class="footer-inner container">
|
<div class="footer-inner container">
|
||||||
<p class="footer-copyright">
|
<p class="footer-copyright">
|
||||||
© ${year} dgray.io - <span data-i18n="footer.rights">${t('footer.rights')}</span>
|
© ${year} kashilo.com - <span data-i18n="footer.rights">${t('footer.rights')}</span>
|
||||||
<span class="footer-swiss">🇨🇭 Made in Switzerland</span>
|
<span class="footer-swiss">🇨🇭 Made in Switzerland</span>
|
||||||
</p>
|
</p>
|
||||||
<span class="xmr-rate" title="CoinGecko">1 XMR ≈ ...</span>
|
<span class="xmr-rate" title="CoinGecko">1 XMR ≈ ...</span>
|
||||||
|
|||||||
@@ -113,9 +113,9 @@ class AppHeader extends HTMLElement {
|
|||||||
render() {
|
render() {
|
||||||
this.innerHTML = /* html */`
|
this.innerHTML = /* html */`
|
||||||
<div class="header-inner container">
|
<div class="header-inner container">
|
||||||
<a href="#/" class="logo" aria-label="dgray.io ${t('common.home')}">
|
<a href="#/" class="logo" aria-label="kashilo.com ${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-light.svg" alt="kashilo.com" 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">
|
<img src="assets/logo-dark.svg" alt="kashilo.com" class="logo-img logo-dark" width="100" height="28">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
|
|||||||
@@ -319,14 +319,14 @@ class AuthModal extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
downloadBackup() {
|
downloadBackup() {
|
||||||
const content = `dgray.io Account Backup
|
const content = `kashilo.com Account Backup
|
||||||
========================
|
========================
|
||||||
|
|
||||||
Your UUID (keep this secret!):
|
Your UUID (keep this secret!):
|
||||||
${this.generatedUuid}
|
${this.generatedUuid}
|
||||||
|
|
||||||
Login URL:
|
Login URL:
|
||||||
https://dgray.io/#/login
|
https://kashilo.com/#/login
|
||||||
|
|
||||||
Created: ${new Date().toISOString()}
|
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 url = URL.createObjectURL(blob)
|
||||||
const a = document.createElement('a')
|
const a = document.createElement('a')
|
||||||
a.href = url
|
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()
|
a.click()
|
||||||
URL.revokeObjectURL(url)
|
URL.revokeObjectURL(url)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class LocationMap extends HTMLElement {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const response = await fetch(`${NOMINATIM_URL}?${params}`, {
|
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()
|
const results = await response.json()
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ class LocationPicker extends HTMLElement {
|
|||||||
|
|
||||||
const response = await fetch(`${NOMINATIM_URL}?${params}`, {
|
const response = await fetch(`${NOMINATIM_URL}?${params}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'dgray.io/1.0'
|
'User-Agent': 'kashilo.com/1.0'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ class PageAbout extends HTMLElement {
|
|||||||
getContent(lang) {
|
getContent(lang) {
|
||||||
const content = {
|
const content = {
|
||||||
de: /* html */`
|
de: /* html */`
|
||||||
<h1>Über dgray.io</h1>
|
<h1>Über kashilo.com</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>
|
<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>
|
<p>Die Bezahlung erfolgt ausschliesslich über Monero (XMR). Kein KYC, keine E-Mail, kein Tracking.</p>
|
||||||
|
|
||||||
<h2>Prinzipien</h2>
|
<h2>Prinzipien</h2>
|
||||||
@@ -29,8 +29,8 @@ class PageAbout extends HTMLElement {
|
|||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
en: /* html */`
|
en: /* html */`
|
||||||
<h1>About dgray.io</h1>
|
<h1>About kashilo.com</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>
|
<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>
|
<p>Payments are made exclusively in Monero (XMR). No KYC, no email, no tracking.</p>
|
||||||
|
|
||||||
<h2>Principles</h2>
|
<h2>Principles</h2>
|
||||||
@@ -43,8 +43,8 @@ class PageAbout extends HTMLElement {
|
|||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
fr: /* html */`
|
fr: /* html */`
|
||||||
<h1>À propos de dgray.io</h1>
|
<h1>À propos de kashilo.com</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>
|
<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>
|
<p>Les paiements s'effectuent exclusivement en Monero (XMR). Pas de KYC, pas d'e-mail, pas de tracking.</p>
|
||||||
|
|
||||||
<h2>Principes</h2>
|
<h2>Principes</h2>
|
||||||
@@ -57,8 +57,8 @@ class PageAbout extends HTMLElement {
|
|||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
it: /* html */`
|
it: /* html */`
|
||||||
<h1>Informazioni su dgray.io</h1>
|
<h1>Informazioni su kashilo.com</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>
|
<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>
|
<p>I pagamenti avvengono esclusivamente in Monero (XMR). Nessun KYC, nessuna email, nessun tracking.</p>
|
||||||
|
|
||||||
<h2>Principi</h2>
|
<h2>Principi</h2>
|
||||||
@@ -71,8 +71,8 @@ class PageAbout extends HTMLElement {
|
|||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
es: /* html */`
|
es: /* html */`
|
||||||
<h1>Acerca de dgray.io</h1>
|
<h1>Acerca de kashilo.com</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>
|
<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>
|
<p>Los pagos se realizan exclusivamente en Monero (XMR). Sin KYC, sin email, sin rastreo.</p>
|
||||||
|
|
||||||
<h2>Principios</h2>
|
<h2>Principios</h2>
|
||||||
@@ -85,8 +85,8 @@ class PageAbout extends HTMLElement {
|
|||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
pt: /* html */`
|
pt: /* html */`
|
||||||
<h1>Sobre o dgray.io</h1>
|
<h1>Sobre o kashilo.com</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>
|
<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>
|
<p>Os pagamentos são feitos exclusivamente em Monero (XMR). Sem KYC, sem email, sem rastreamento.</p>
|
||||||
|
|
||||||
<h2>Princípios</h2>
|
<h2>Princípios</h2>
|
||||||
@@ -99,8 +99,8 @@ class PageAbout extends HTMLElement {
|
|||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
ru: /* html */`
|
ru: /* html */`
|
||||||
<h1>О dgray.io</h1>
|
<h1>О kashilo.com</h1>
|
||||||
<p>dgray.io — это платформа объявлений с приоритетом конфиденциальности. Пользователи могут создавать объявления и общаться через сквозное шифрование — без раскрытия личных данных.</p>
|
<p>kashilo.com — это платформа объявлений с приоритетом конфиденциальности. Пользователи могут создавать объявления и общаться через сквозное шифрование — без раскрытия личных данных.</p>
|
||||||
<p>Оплата осуществляется исключительно в Monero (XMR). Без KYC, без email, без отслеживания.</p>
|
<p>Оплата осуществляется исключительно в Monero (XMR). Без KYC, без email, без отслеживания.</p>
|
||||||
|
|
||||||
<h2>Принципы</h2>
|
<h2>Принципы</h2>
|
||||||
|
|||||||
@@ -17,17 +17,17 @@ class PageContact extends HTMLElement {
|
|||||||
de: /* html */`
|
de: /* html */`
|
||||||
<h1>Kontakt</h1>
|
<h1>Kontakt</h1>
|
||||||
<p>Bei Fragen oder Problemen erreichst du uns unter:</p>
|
<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 */`
|
en: /* html */`
|
||||||
<h1>Contact</h1>
|
<h1>Contact</h1>
|
||||||
<p>For questions or issues, reach us at:</p>
|
<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 */`
|
fr: /* html */`
|
||||||
<h1>Contact</h1>
|
<h1>Contact</h1>
|
||||||
<p>Pour toute question ou problème, contactez-nous à :</p>
|
<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
|
return content[lang] || content.de
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import '../location-picker.js'
|
|||||||
import '../pow-captcha.js'
|
import '../pow-captcha.js'
|
||||||
import '../image-cropper.js'
|
import '../image-cropper.js'
|
||||||
|
|
||||||
const STORAGE_KEY = 'dgray_create_draft'
|
const STORAGE_KEY = 'kashilo_create_draft'
|
||||||
|
|
||||||
class PageCreate extends HTMLElement {
|
class PageCreate extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class PageImprint extends HTMLElement {
|
|||||||
de: /* html */`
|
de: /* html */`
|
||||||
<h1>Impressum</h1>
|
<h1>Impressum</h1>
|
||||||
<div class="legal-draft-notice">ENTWURF — Bitte durch eine Fachperson prüfen lassen.</div>
|
<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>
|
<h2>1. Angaben gemäss Schweizer Recht</h2>
|
||||||
<p>Verantwortlich für diese Website:</p>
|
<p>Verantwortlich für diese Website:</p>
|
||||||
@@ -49,7 +49,7 @@ class PageImprint extends HTMLElement {
|
|||||||
en: /* html */`
|
en: /* html */`
|
||||||
<h1>Legal Notice</h1>
|
<h1>Legal Notice</h1>
|
||||||
<div class="legal-draft-notice">DRAFT — Please have this reviewed by a legal professional.</div>
|
<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>
|
<h2>1. Information according to Swiss law</h2>
|
||||||
<p>Responsible for this website:</p>
|
<p>Responsible for this website:</p>
|
||||||
@@ -81,7 +81,7 @@ class PageImprint extends HTMLElement {
|
|||||||
fr: /* html */`
|
fr: /* html */`
|
||||||
<h1>Mentions légales</h1>
|
<h1>Mentions légales</h1>
|
||||||
<div class="legal-draft-notice">ÉBAUCHE — Veuillez faire vérifier ce document par un professionnel du droit.</div>
|
<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>
|
<h2>1. Informations selon le droit suisse</h2>
|
||||||
<p>Responsable de ce site web :</p>
|
<p>Responsable de ce site web :</p>
|
||||||
@@ -113,7 +113,7 @@ class PageImprint extends HTMLElement {
|
|||||||
it: /* html */`
|
it: /* html */`
|
||||||
<h1>Avviso legale</h1>
|
<h1>Avviso legale</h1>
|
||||||
<div class="legal-draft-notice">BOZZA — Si prega di far verificare questo documento da un professionista legale.</div>
|
<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>
|
<h2>1. Informazioni secondo il diritto svizzero</h2>
|
||||||
<p>Responsabile di questo sito web:</p>
|
<p>Responsabile di questo sito web:</p>
|
||||||
@@ -145,7 +145,7 @@ class PageImprint extends HTMLElement {
|
|||||||
es: /* html */`
|
es: /* html */`
|
||||||
<h1>Aviso legal</h1>
|
<h1>Aviso legal</h1>
|
||||||
<div class="legal-draft-notice">BORRADOR — Por favor, haga revisar este documento por un profesional legal.</div>
|
<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>
|
<h2>1. Información según la legislación suiza</h2>
|
||||||
<p>Responsable de este sitio web:</p>
|
<p>Responsable de este sitio web:</p>
|
||||||
@@ -177,7 +177,7 @@ class PageImprint extends HTMLElement {
|
|||||||
pt: /* html */`
|
pt: /* html */`
|
||||||
<h1>Aviso legal</h1>
|
<h1>Aviso legal</h1>
|
||||||
<div class="legal-draft-notice">RASCUNHO — Por favor, solicite a revisão deste documento por um profissional jurídico.</div>
|
<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>
|
<h2>1. Informações conforme a legislação suíça</h2>
|
||||||
<p>Responsável por este site:</p>
|
<p>Responsável por este site:</p>
|
||||||
@@ -209,7 +209,7 @@ class PageImprint extends HTMLElement {
|
|||||||
ru: /* html */`
|
ru: /* html */`
|
||||||
<h1>Правовая информация</h1>
|
<h1>Правовая информация</h1>
|
||||||
<div class="legal-draft-notice">ЧЕРНОВИК — Пожалуйста, передайте этот документ на проверку юристу.</div>
|
<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>
|
<h2>1. Сведения согласно швейцарскому праву</h2>
|
||||||
<p>Ответственный за данный сайт:</p>
|
<p>Ответственный за данный сайт:</p>
|
||||||
|
|||||||
@@ -90,11 +90,11 @@ class PageListing extends HTMLElement {
|
|||||||
updateMetaTags() {
|
updateMetaTags() {
|
||||||
if (!this.listing) return
|
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 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 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 imageUrl = imageId ? directus.getFileUrl(imageId, { width: 1200, height: 630, fit: 'cover' }) : 'https://kashilo.com/assets/press/og-image.png'
|
||||||
const url = `https://dgray.io/#/listing/${this.listing.id}`
|
const url = `https://kashilo.com/#/listing/${this.listing.id}`
|
||||||
|
|
||||||
document.title = title
|
document.title = title
|
||||||
this._setMeta('description', description)
|
this._setMeta('description', description)
|
||||||
@@ -109,16 +109,16 @@ class PageListing extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetMetaTags() {
|
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 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
|
document.title = defaultTitle
|
||||||
this._setMeta('description', defaultDesc)
|
this._setMeta('description', defaultDesc)
|
||||||
this._setMeta('og:title', defaultTitle, true)
|
this._setMeta('og:title', defaultTitle, true)
|
||||||
this._setMeta('og:description', defaultDesc, true)
|
this._setMeta('og:description', defaultDesc, true)
|
||||||
this._setMeta('og:image', defaultImage, 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('og:type', 'website', true)
|
||||||
this._setMeta('twitter:title', defaultTitle)
|
this._setMeta('twitter:title', defaultTitle)
|
||||||
this._setMeta('twitter:description', defaultDesc)
|
this._setMeta('twitter:description', defaultDesc)
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ class PagePrivacy extends HTMLElement {
|
|||||||
const content = {
|
const content = {
|
||||||
de: /* html */`
|
de: /* html */`
|
||||||
<h1>Datenschutzerklärung</h1>
|
<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>
|
<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>
|
<h2>2. Grundsatz</h2>
|
||||||
<p>Die Plattform wurde nach dem Prinzip der Datensparsamkeit konzipiert.</p>
|
<p>Die Plattform wurde nach dem Prinzip der Datensparsamkeit konzipiert.</p>
|
||||||
@@ -67,10 +67,10 @@ class PagePrivacy extends HTMLElement {
|
|||||||
`,
|
`,
|
||||||
en: /* html */`
|
en: /* html */`
|
||||||
<h1>Privacy Policy</h1>
|
<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>
|
<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>
|
<h2>2. Principle</h2>
|
||||||
<p>The platform was designed following the principle of data minimization.</p>
|
<p>The platform was designed following the principle of data minimization.</p>
|
||||||
@@ -118,10 +118,10 @@ class PagePrivacy extends HTMLElement {
|
|||||||
`,
|
`,
|
||||||
fr: /* html */`
|
fr: /* html */`
|
||||||
<h1>Politique de confidentialité</h1>
|
<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>
|
<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>
|
<h2>2. Principe</h2>
|
||||||
<p>La plateforme a été conçue selon le principe de minimisation des données.</p>
|
<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 */`
|
it: /* html */`
|
||||||
<h1>Informativa sulla privacy</h1>
|
<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>
|
<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>
|
<h2>2. Principio</h2>
|
||||||
<p>La piattaforma è stata progettata secondo il principio della minimizzazione dei dati.</p>
|
<p>La piattaforma è stata progettata secondo il principio della minimizzazione dei dati.</p>
|
||||||
@@ -220,10 +220,10 @@ class PagePrivacy extends HTMLElement {
|
|||||||
`,
|
`,
|
||||||
es: /* html */`
|
es: /* html */`
|
||||||
<h1>Política de Privacidad</h1>
|
<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>
|
<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>
|
<h2>2. Principio</h2>
|
||||||
<p>La plataforma fue diseñada según el principio de minimización de datos.</p>
|
<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 */`
|
pt: /* html */`
|
||||||
<h1>Política de Privacidade</h1>
|
<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>
|
<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>
|
<h2>2. Princípio</h2>
|
||||||
<p>A plataforma foi projetada segundo o princípio da minimização de dados.</p>
|
<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 */`
|
ru: /* html */`
|
||||||
<h1>Политика конфиденциальности</h1>
|
<h1>Политика конфиденциальности</h1>
|
||||||
<p class="legal-meta">dgray.io — Анонимный маркетплейс | Обновлено: февраль 2026</p>
|
<p class="legal-meta">kashilo.com — Анонимный маркетплейс | Обновлено: февраль 2026</p>
|
||||||
|
|
||||||
<h2>1. Ответственный за обработку данных</h2>
|
<h2>1. Ответственный за обработку данных</h2>
|
||||||
<p>Ответственным за обработку данных является оператор платформы dgray.io с местонахождением в Швейцарии.</p>
|
<p>Ответственным за обработку данных является оператор платформы kashilo.com с местонахождением в Швейцарии.</p>
|
||||||
|
|
||||||
<h2>2. Принцип</h2>
|
<h2>2. Принцип</h2>
|
||||||
<p>Платформа разработана по принципу минимизации данных.</p>
|
<p>Платформа разработана по принципу минимизации данных.</p>
|
||||||
|
|||||||
@@ -146,11 +146,11 @@ class PageSettings extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrentCurrency() {
|
getCurrentCurrency() {
|
||||||
return localStorage.getItem('dgray_currency') || 'USD'
|
return localStorage.getItem('kashilo_currency') || 'USD'
|
||||||
}
|
}
|
||||||
|
|
||||||
async setCurrency(currency) {
|
async setCurrency(currency) {
|
||||||
localStorage.setItem('dgray_currency', currency)
|
localStorage.setItem('kashilo_currency', currency)
|
||||||
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
|
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
|
||||||
|
|
||||||
// Save to user profile if logged in
|
// Save to user profile if logged in
|
||||||
@@ -323,7 +323,7 @@ class PageSettings extends HTMLElement {
|
|||||||
<a href="#/privacy">${t('footer.privacy')}</a>
|
<a href="#/privacy">${t('footer.privacy')}</a>
|
||||||
<a href="#/terms">${t('footer.terms')}</a>
|
<a href="#/terms">${t('footer.terms')}</a>
|
||||||
</div>
|
</div>
|
||||||
<p class="version">dgray.io v1.0.0</p>
|
<p class="version">kashilo.com v1.0.0</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ class PageTerms extends HTMLElement {
|
|||||||
getContentDE() {
|
getContentDE() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Allgemeine Geschäftsbedingungen (AGB)</h1>
|
<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>
|
<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.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>
|
<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() {
|
getContentEN() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Terms of Service</h1>
|
<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>
|
<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.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>
|
<p>1.3 By using the platform, the user agrees to these terms.</p>
|
||||||
|
|
||||||
@@ -188,10 +188,10 @@ class PageTerms extends HTMLElement {
|
|||||||
getContentFR() {
|
getContentFR() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Conditions Générales d'Utilisation (CGU)</h1>
|
<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>
|
<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.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>
|
<p>1.3 En utilisant la plateforme, l'utilisateur accepte les présentes CGU.</p>
|
||||||
|
|
||||||
@@ -262,10 +262,10 @@ class PageTerms extends HTMLElement {
|
|||||||
getContentIT() {
|
getContentIT() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Condizioni generali di utilizzo (CGU)</h1>
|
<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>
|
<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.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>
|
<p>1.3 Utilizzando la piattaforma, l'utente accetta le presenti CGU.</p>
|
||||||
|
|
||||||
@@ -336,10 +336,10 @@ class PageTerms extends HTMLElement {
|
|||||||
getContentES() {
|
getContentES() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Condiciones generales de uso (CGU)</h1>
|
<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>
|
<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.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>
|
<p>1.3 Al utilizar la plataforma, el usuario acepta las presentes CGU.</p>
|
||||||
|
|
||||||
@@ -410,10 +410,10 @@ class PageTerms extends HTMLElement {
|
|||||||
getContentPT() {
|
getContentPT() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Termos de Uso</h1>
|
<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>
|
<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.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>
|
<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() {
|
getContentRU() {
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<h1>Условия использования</h1>
|
<h1>Условия использования</h1>
|
||||||
<p class="legal-meta">dgray.io — Анонимный маркетплейс | Обновлено: февраль 2026</p>
|
<p class="legal-meta">kashilo.com — Анонимный маркетплейс | Обновлено: февраль 2026</p>
|
||||||
|
|
||||||
<h2>1. Область применения</h2>
|
<h2>1. Область применения</h2>
|
||||||
<p>1.1 Настоящие Условия использования регулируют пользование платформой dgray.io.</p>
|
<p>1.1 Настоящие Условия использования регулируют пользование платформой kashilo.com.</p>
|
||||||
<p>1.2 Платформа управляется физическим лицом с местонахождением в Швейцарии.</p>
|
<p>1.2 Платформа управляется физическим лицом с местонахождением в Швейцарии.</p>
|
||||||
<p>1.3 Используя платформу, пользователь соглашается с настоящими Условиями использования.</p>
|
<p>1.3 Используя платформу, пользователь соглашается с настоящими Условиями использования.</p>
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import { setPersist, getPersist } from './directus/client.js'
|
|||||||
import { cryptoService } from './crypto.js'
|
import { cryptoService } from './crypto.js'
|
||||||
import { i18n } from '../i18n.js'
|
import { i18n } from '../i18n.js'
|
||||||
|
|
||||||
const AUTH_DOMAIN = 'dgray.io'
|
const AUTH_DOMAIN = 'kashilo.com'
|
||||||
|
|
||||||
class AuthService {
|
class AuthService {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.currentUser = null
|
this.currentUser = null
|
||||||
this.listeners = new Set()
|
this.listeners = new Set()
|
||||||
this.hashCache = new Map()
|
this.hashCache = new Map()
|
||||||
if (localStorage.getItem('dgray_remember') === '1') {
|
if (localStorage.getItem('kashilo_remember') === '1') {
|
||||||
setPersist(true)
|
setPersist(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ class AuthService {
|
|||||||
|
|
||||||
this.currentUser = null
|
this.currentUser = null
|
||||||
this.clearStoredUuid()
|
this.clearStoredUuid()
|
||||||
localStorage.removeItem('dgray_remember')
|
localStorage.removeItem('kashilo_remember')
|
||||||
setPersist(false)
|
setPersist(false)
|
||||||
cryptoService.lock()
|
cryptoService.lock()
|
||||||
this.resetPreferencesToDefaults()
|
this.resetPreferencesToDefaults()
|
||||||
@@ -159,7 +159,7 @@ class AuthService {
|
|||||||
const keysToRemove = []
|
const keysToRemove = []
|
||||||
for (let i = 0; i < localStorage.length; i++) {
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
const key = localStorage.key(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))
|
keysToRemove.forEach(k => localStorage.removeItem(k))
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ class AuthService {
|
|||||||
|
|
||||||
for (let i = sessionStorage.length - 1; i >= 0; i--) {
|
for (let i = sessionStorage.length - 1; i >= 0; i--) {
|
||||||
const key = sessionStorage.key(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 defaultCurrency = 'USD'
|
||||||
const defaultLocale = 'en'
|
const defaultLocale = 'en'
|
||||||
|
|
||||||
localStorage.setItem('dgray_currency', defaultCurrency)
|
localStorage.setItem('kashilo_currency', defaultCurrency)
|
||||||
localStorage.setItem('locale', defaultLocale)
|
localStorage.setItem('locale', defaultLocale)
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency: defaultCurrency } }))
|
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency: defaultCurrency } }))
|
||||||
@@ -223,7 +223,7 @@ class AuthService {
|
|||||||
|
|
||||||
if (this.currentUser.preferred_currency) {
|
if (this.currentUser.preferred_currency) {
|
||||||
const currency = 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 } }))
|
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
|
||||||
}
|
}
|
||||||
if (this.currentUser.preferred_locale) {
|
if (this.currentUser.preferred_locale) {
|
||||||
@@ -261,7 +261,7 @@ class AuthService {
|
|||||||
*/
|
*/
|
||||||
storeUuid(uuid) {
|
storeUuid(uuid) {
|
||||||
const storage = getPersist() ? localStorage : sessionStorage
|
const storage = getPersist() ? localStorage : sessionStorage
|
||||||
storage.setItem('dgray_uuid', uuid)
|
storage.setItem('kashilo_uuid', uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,28 +269,28 @@ class AuthService {
|
|||||||
* @returns {string|null}
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
getStoredUuid() {
|
getStoredUuid() {
|
||||||
return sessionStorage.getItem('dgray_uuid') || localStorage.getItem('dgray_uuid')
|
return sessionStorage.getItem('kashilo_uuid') || localStorage.getItem('kashilo_uuid')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears stored UUID
|
* Clears stored UUID
|
||||||
*/
|
*/
|
||||||
clearStoredUuid() {
|
clearStoredUuid() {
|
||||||
sessionStorage.removeItem('dgray_uuid')
|
sessionStorage.removeItem('kashilo_uuid')
|
||||||
localStorage.removeItem('dgray_uuid')
|
localStorage.removeItem('kashilo_uuid')
|
||||||
}
|
}
|
||||||
|
|
||||||
setRememberMe(value) {
|
setRememberMe(value) {
|
||||||
setPersist(value)
|
setPersist(value)
|
||||||
if (value) {
|
if (value) {
|
||||||
localStorage.setItem('dgray_remember', '1')
|
localStorage.setItem('kashilo_remember', '1')
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('dgray_remember')
|
localStorage.removeItem('kashilo_remember')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRememberMe() {
|
getRememberMe() {
|
||||||
return localStorage.getItem('dgray_remember') === '1'
|
return localStorage.getItem('kashilo_remember') === '1'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { i18n } from '../i18n.js'
|
import { i18n } from '../i18n.js'
|
||||||
|
|
||||||
const POW_SERVER = 'https://pow.dgray.io'
|
const POW_SERVER = 'https://pow.kashilo.com'
|
||||||
|
|
||||||
let modalScriptLoaded = false
|
let modalScriptLoaded = false
|
||||||
let modalScriptLoading = null
|
let modalScriptLoading = null
|
||||||
@@ -131,7 +131,7 @@ export async function pollUntilDone(invoiceId, options = {}) {
|
|||||||
*/
|
*/
|
||||||
export function getPendingInvoice(listingId) {
|
export function getPendingInvoice(listingId) {
|
||||||
try {
|
try {
|
||||||
const data = localStorage.getItem(`dgray_invoice_${listingId}`)
|
const data = localStorage.getItem(`kashilo_invoice_${listingId}`)
|
||||||
return data ? JSON.parse(data) : null
|
return data ? JSON.parse(data) : null
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return null
|
return null
|
||||||
@@ -145,7 +145,7 @@ export function getPendingInvoice(listingId) {
|
|||||||
*/
|
*/
|
||||||
export function savePendingInvoice(listingId, invoiceId) {
|
export function savePendingInvoice(listingId, invoiceId) {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(`dgray_invoice_${listingId}`, JSON.stringify({
|
localStorage.setItem(`kashilo_invoice_${listingId}`, JSON.stringify({
|
||||||
invoiceId,
|
invoiceId,
|
||||||
createdAt: Date.now()
|
createdAt: Date.now()
|
||||||
}))
|
}))
|
||||||
@@ -159,7 +159,7 @@ export function savePendingInvoice(listingId, invoiceId) {
|
|||||||
* @param {string} listingId
|
* @param {string} listingId
|
||||||
*/
|
*/
|
||||||
export function clearPendingInvoice(listingId) {
|
export function clearPendingInvoice(listingId) {
|
||||||
localStorage.removeItem(`dgray_invoice_${listingId}`)
|
localStorage.removeItem(`kashilo_invoice_${listingId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ class CategoriesService {
|
|||||||
this.cache = null
|
this.cache = null
|
||||||
this.cacheTimestamp = 0
|
this.cacheTimestamp = 0
|
||||||
this.cacheTimeout = 24 * 60 * 60 * 1000 // 24 hours
|
this.cacheTimeout = 24 * 60 * 60 * 1000 // 24 hours
|
||||||
this.storageKey = 'dgray_categories'
|
this.storageKey = 'kashilo_categories'
|
||||||
this.storageTimestampKey = 'dgray_categories_ts'
|
this.storageTimestampKey = 'kashilo_categories_ts'
|
||||||
this._pending = null
|
this._pending = null
|
||||||
this._loadFromStorage()
|
this._loadFromStorage()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
* derived from the user's UUID via PBKDF2.
|
* derived from the user's UUID via PBKDF2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const STORAGE_KEY = 'dgray_keypair'
|
const STORAGE_KEY = 'kashilo_keypair'
|
||||||
const SALT_KEY = 'dgray_keypair_salt'
|
const SALT_KEY = 'kashilo_keypair_salt'
|
||||||
const LISTING_KEYS_STORAGE = 'dgray_listing_keys'
|
const LISTING_KEYS_STORAGE = 'kashilo_listing_keys'
|
||||||
|
|
||||||
class CryptoService {
|
class CryptoService {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export function convertFiat(amount, fromCurrency, toCurrency, rates) {
|
|||||||
* @returns {string} Currency code (default: 'USD')
|
* @returns {string} Currency code (default: 'USD')
|
||||||
*/
|
*/
|
||||||
export function getDisplayCurrency() {
|
export function getDisplayCurrency() {
|
||||||
return localStorage.getItem('dgray_currency') || 'USD'
|
return localStorage.getItem('kashilo_currency') || 'USD'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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.
|
* Re-exports modular sub-services as a single backward-compatible singleton.
|
||||||
* @module services/directus
|
* @module services/directus
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const DIRECTUS_URL = 'https://api.dgray.io'
|
const DIRECTUS_URL = 'https://api.kashilo.com'
|
||||||
|
|
||||||
let _persist = false
|
let _persist = false
|
||||||
|
|
||||||
@@ -51,14 +51,14 @@ class DirectusClient {
|
|||||||
// ── Token Management ──
|
// ── Token Management ──
|
||||||
|
|
||||||
loadTokens() {
|
loadTokens() {
|
||||||
const stored = sessionStorage.getItem('dgray_auth') || localStorage.getItem('dgray_auth')
|
const stored = sessionStorage.getItem('kashilo_auth') || localStorage.getItem('kashilo_auth')
|
||||||
if (stored) {
|
if (stored) {
|
||||||
try {
|
try {
|
||||||
const { accessToken, refreshToken, expiry } = JSON.parse(stored)
|
const { accessToken, refreshToken, expiry } = JSON.parse(stored)
|
||||||
this.accessToken = accessToken
|
this.accessToken = accessToken
|
||||||
this.refreshToken = refreshToken
|
this.refreshToken = refreshToken
|
||||||
this.tokenExpiry = expiry
|
this.tokenExpiry = expiry
|
||||||
if (localStorage.getItem('dgray_auth')) {
|
if (localStorage.getItem('kashilo_auth')) {
|
||||||
_persist = true
|
_persist = true
|
||||||
}
|
}
|
||||||
this.scheduleTokenRefresh()
|
this.scheduleTokenRefresh()
|
||||||
@@ -73,7 +73,7 @@ class DirectusClient {
|
|||||||
this.refreshToken = refreshToken
|
this.refreshToken = refreshToken
|
||||||
this.tokenExpiry = Date.now() + (expiresIn * 1000)
|
this.tokenExpiry = Date.now() + (expiresIn * 1000)
|
||||||
|
|
||||||
_storage().setItem('dgray_auth', JSON.stringify({
|
_storage().setItem('kashilo_auth', JSON.stringify({
|
||||||
accessToken: this.accessToken,
|
accessToken: this.accessToken,
|
||||||
refreshToken: this.refreshToken,
|
refreshToken: this.refreshToken,
|
||||||
expiry: this.tokenExpiry
|
expiry: this.tokenExpiry
|
||||||
@@ -86,8 +86,8 @@ class DirectusClient {
|
|||||||
this.accessToken = null
|
this.accessToken = null
|
||||||
this.refreshToken = null
|
this.refreshToken = null
|
||||||
this.tokenExpiry = null
|
this.tokenExpiry = null
|
||||||
sessionStorage.removeItem('dgray_auth')
|
sessionStorage.removeItem('kashilo_auth')
|
||||||
localStorage.removeItem('dgray_auth')
|
localStorage.removeItem('kashilo_auth')
|
||||||
|
|
||||||
if (this.refreshTimeout) {
|
if (this.refreshTimeout) {
|
||||||
clearTimeout(this.refreshTimeout)
|
clearTimeout(this.refreshTimeout)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { directus } from './directus.js'
|
import { directus } from './directus.js'
|
||||||
import { auth } from './auth.js'
|
import { auth } from './auth.js'
|
||||||
|
|
||||||
const ANON_KEY = 'dgray_favorites'
|
const ANON_KEY = 'kashilo_favorites'
|
||||||
|
|
||||||
class FavoritesService {
|
class FavoritesService {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Stores seller contact keys on first use, warns on key changes
|
* 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 {
|
class KeyPinningService {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
// Client must find nonce where SHA256(challenge + nonce) has N leading zeros
|
// Client must find nonce where SHA256(challenge + nonce) has N leading zeros
|
||||||
// Server-first: tries /pow/challenge endpoint, falls back to local generation
|
// 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 DIFFICULTY = 4
|
||||||
const SERVER_TIMEOUT_MS = 1500
|
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) {
|
async function hmacSign(message) {
|
||||||
const enc = new TextEncoder()
|
const enc = new TextEncoder()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"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."
|
"description": "Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Impressum"
|
"imprint": "Impressum"
|
||||||
},
|
},
|
||||||
"home": {
|
"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.",
|
"subtitle": "Finde tolle Angebote in deiner Nähe oder verkaufe, was du nicht mehr brauchst.",
|
||||||
"browseListings": "Anzeigen durchsuchen",
|
"browseListings": "Anzeigen durchsuchen",
|
||||||
"createListing": "Anzeige erstellen",
|
"createListing": "Anzeige erstellen",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"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."
|
"description": "Buy and sell without an account, without email. Pay with Monero. End-to-end encrypted chat."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Legal Notice"
|
"imprint": "Legal Notice"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"title": "Welcome to dgray.io",
|
"title": "Welcome to kashilo.com",
|
||||||
"subtitle": "Find great deals near you or sell what you no longer need.",
|
"subtitle": "Find great deals near you or sell what you no longer need.",
|
||||||
"browseListings": "Browse Listings",
|
"browseListings": "Browse Listings",
|
||||||
"createListing": "Create Listing",
|
"createListing": "Create Listing",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"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."
|
"description": "Compra y vende sin cuenta, sin email. Pago con Monero. Chat cifrado de extremo a extremo."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Aviso legal"
|
"imprint": "Aviso legal"
|
||||||
},
|
},
|
||||||
"home": {
|
"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.",
|
"subtitle": "Encuentra grandes ofertas cerca de ti o vende lo que ya no necesitas.",
|
||||||
"browseListings": "Explorar anuncios",
|
"browseListings": "Explorar anuncios",
|
||||||
"createListing": "Crear anuncio",
|
"createListing": "Crear anuncio",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"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."
|
"description": "Achetez et vendez sans compte, sans e-mail. Paiement en Monero. Chat chiffré de bout en bout."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Mentions légales"
|
"imprint": "Mentions légales"
|
||||||
},
|
},
|
||||||
"home": {
|
"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.",
|
"subtitle": "Trouvez de bonnes affaires près de chez vous ou vendez ce dont vous n'avez plus besoin.",
|
||||||
"browseListings": "Parcourir les annonces",
|
"browseListings": "Parcourir les annonces",
|
||||||
"createListing": "Créer une annonce",
|
"createListing": "Créer une annonce",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"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."
|
"description": "Compra e vendi senza account, senza email. Pagamento in Monero. Chat crittografata end-to-end."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Avviso legale"
|
"imprint": "Avviso legale"
|
||||||
},
|
},
|
||||||
"home": {
|
"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ù.",
|
"subtitle": "Trova ottime offerte vicino a te o vendi ciò che non ti serve più.",
|
||||||
"browseListings": "Sfoglia annunci",
|
"browseListings": "Sfoglia annunci",
|
||||||
"createListing": "Crea annuncio",
|
"createListing": "Crea annuncio",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"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."
|
"description": "Compre e venda sem conta, sem email. Pagamento com Monero. Chat criptografado ponta a ponta."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Aviso legal"
|
"imprint": "Aviso legal"
|
||||||
},
|
},
|
||||||
"home": {
|
"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.",
|
"subtitle": "Encontre boas ofertas perto de você ou venda o que não precisa mais.",
|
||||||
"browseListings": "Ver Anúncios",
|
"browseListings": "Ver Anúncios",
|
||||||
"createListing": "Criar Anúncio",
|
"createListing": "Criar Anúncio",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"title": "dgray.io – Анонимные объявления",
|
"title": "kashilo.com – Анонимные объявления",
|
||||||
"description": "Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата."
|
"description": "Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"imprint": "Правовая информация"
|
"imprint": "Правовая информация"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"title": "Добро пожаловать на dgray.io",
|
"title": "Добро пожаловать на kashilo.com",
|
||||||
"subtitle": "Находите выгодные предложения рядом или продавайте ненужное.",
|
"subtitle": "Находите выгодные предложения рядом или продавайте ненужное.",
|
||||||
"browseListings": "Смотреть объявления",
|
"browseListings": "Смотреть объявления",
|
||||||
"createListing": "Создать объявление",
|
"createListing": "Создать объявление",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dgray.io - marketplace",
|
"name": "kashilo.com - marketplace",
|
||||||
"short_name": "dgray.io",
|
"short_name": "kashilo.com",
|
||||||
"description": "Anonymous marketplace with Monero payment",
|
"description": "Anonymous marketplace with Monero payment",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const CACHE_NAME = 'dgray-v51';
|
const CACHE_NAME = 'kashilo-v51';
|
||||||
const STATIC_ASSETS = [
|
const STATIC_ASSETS = [
|
||||||
'/',
|
'/',
|
||||||
'/index.html',
|
'/index.html',
|
||||||
@@ -108,7 +108,7 @@ self.addEventListener('fetch', (event) => {
|
|||||||
if (request.method !== 'GET') return;
|
if (request.method !== 'GET') return;
|
||||||
|
|
||||||
// API calls: Network First (external API domain)
|
// API calls: Network First (external API domain)
|
||||||
if (url.hostname === 'api.dgray.io') {
|
if (url.hostname === 'api.kashilo.com') {
|
||||||
event.respondWith(networkFirst(request));
|
event.respondWith(networkFirst(request));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ describe('DirectusClient token management', () => {
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
client.clearTokens()
|
client.clearTokens()
|
||||||
sessionStorage.removeItem('dgray_auth')
|
sessionStorage.removeItem('kashilo_auth')
|
||||||
localStorage.removeItem('dgray_auth')
|
localStorage.removeItem('kashilo_auth')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('isAuthenticated returns true with valid token', () => {
|
test('isAuthenticated returns true with valid token', () => {
|
||||||
@@ -145,8 +145,8 @@ describe('DirectusClient token management', () => {
|
|||||||
assertTrue(client.isAuthenticated())
|
assertTrue(client.isAuthenticated())
|
||||||
|
|
||||||
client.clearTokens()
|
client.clearTokens()
|
||||||
sessionStorage.removeItem('dgray_auth')
|
sessionStorage.removeItem('kashilo_auth')
|
||||||
localStorage.removeItem('dgray_auth')
|
localStorage.removeItem('kashilo_auth')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('isAuthenticated returns false when token expired', () => {
|
test('isAuthenticated returns false when token expired', () => {
|
||||||
@@ -163,22 +163,22 @@ describe('DirectusClient token management', () => {
|
|||||||
refreshToken: 'stored-refresh',
|
refreshToken: 'stored-refresh',
|
||||||
expiry: Date.now() + 600000
|
expiry: Date.now() + 600000
|
||||||
})
|
})
|
||||||
sessionStorage.setItem('dgray_auth', authData)
|
sessionStorage.setItem('kashilo_auth', authData)
|
||||||
|
|
||||||
client.loadTokens()
|
client.loadTokens()
|
||||||
assertEquals(client.accessToken, 'stored-access')
|
assertEquals(client.accessToken, 'stored-access')
|
||||||
assertEquals(client.refreshToken, 'stored-refresh')
|
assertEquals(client.refreshToken, 'stored-refresh')
|
||||||
|
|
||||||
client.clearTokens()
|
client.clearTokens()
|
||||||
sessionStorage.removeItem('dgray_auth')
|
sessionStorage.removeItem('kashilo_auth')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('loadTokens clears on invalid JSON', () => {
|
test('loadTokens clears on invalid JSON', () => {
|
||||||
sessionStorage.setItem('dgray_auth', 'not-json')
|
sessionStorage.setItem('kashilo_auth', 'not-json')
|
||||||
client.loadTokens()
|
client.loadTokens()
|
||||||
assertEquals(client.accessToken, null)
|
assertEquals(client.accessToken, null)
|
||||||
|
|
||||||
sessionStorage.removeItem('dgray_auth')
|
sessionStorage.removeItem('kashilo_auth')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ describe('CryptoService', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
asyncTest('unlock generates keypair and stores encrypted', async () => {
|
asyncTest('unlock generates keypair and stores encrypted', async () => {
|
||||||
localStorage.removeItem('dgray_keypair')
|
localStorage.removeItem('kashilo_keypair')
|
||||||
localStorage.removeItem('dgray_keypair_salt')
|
localStorage.removeItem('kashilo_keypair_salt')
|
||||||
|
|
||||||
await cryptoService.unlock(TEST_UUID)
|
await cryptoService.unlock(TEST_UUID)
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ describe('CryptoService', () => {
|
|||||||
assertTrue(cryptoService.getPublicKey() !== null)
|
assertTrue(cryptoService.getPublicKey() !== null)
|
||||||
assertTrue(cryptoService.getPublicKey().length > 10)
|
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.ct !== undefined, 'stored keypair should be encrypted (has ct)')
|
||||||
assertTrue(stored.iv !== undefined, 'stored keypair should be encrypted (has iv)')
|
assertTrue(stored.iv !== undefined, 'stored keypair should be encrypted (has iv)')
|
||||||
assertFalse(stored.publicKey !== undefined, 'stored keypair should NOT have plaintext publicKey')
|
assertFalse(stored.publicKey !== undefined, 'stored keypair should NOT have plaintext publicKey')
|
||||||
@@ -77,7 +77,7 @@ describe('CryptoService', () => {
|
|||||||
cryptoService.lock()
|
cryptoService.lock()
|
||||||
assertEquals(cryptoService.keyPair, null)
|
assertEquals(cryptoService.keyPair, null)
|
||||||
|
|
||||||
assertTrue(localStorage.getItem('dgray_keypair') !== null)
|
assertTrue(localStorage.getItem('kashilo_keypair') !== null)
|
||||||
})
|
})
|
||||||
|
|
||||||
asyncTest('destroyKeyPair clears memory and storage', async () => {
|
asyncTest('destroyKeyPair clears memory and storage', async () => {
|
||||||
@@ -85,8 +85,8 @@ describe('CryptoService', () => {
|
|||||||
cryptoService.destroyKeyPair()
|
cryptoService.destroyKeyPair()
|
||||||
|
|
||||||
assertEquals(cryptoService.keyPair, null)
|
assertEquals(cryptoService.keyPair, null)
|
||||||
assertEquals(localStorage.getItem('dgray_keypair'), null)
|
assertEquals(localStorage.getItem('kashilo_keypair'), null)
|
||||||
assertEquals(localStorage.getItem('dgray_keypair_salt'), null)
|
assertEquals(localStorage.getItem('kashilo_keypair_salt'), null)
|
||||||
})
|
})
|
||||||
|
|
||||||
asyncTest('migrates plaintext keypair to encrypted on unlock', async () => {
|
asyncTest('migrates plaintext keypair to encrypted on unlock', async () => {
|
||||||
@@ -96,14 +96,14 @@ describe('CryptoService', () => {
|
|||||||
publicKey: cryptoService.naclUtil.encodeBase64(kp.publicKey),
|
publicKey: cryptoService.naclUtil.encodeBase64(kp.publicKey),
|
||||||
secretKey: cryptoService.naclUtil.encodeBase64(kp.secretKey)
|
secretKey: cryptoService.naclUtil.encodeBase64(kp.secretKey)
|
||||||
}
|
}
|
||||||
localStorage.setItem('dgray_keypair', JSON.stringify(plaintext))
|
localStorage.setItem('kashilo_keypair', JSON.stringify(plaintext))
|
||||||
localStorage.removeItem('dgray_keypair_salt')
|
localStorage.removeItem('kashilo_keypair_salt')
|
||||||
|
|
||||||
await cryptoService.unlock(TEST_UUID)
|
await cryptoService.unlock(TEST_UUID)
|
||||||
|
|
||||||
assertEquals(cryptoService.getPublicKey(), plaintext.publicKey)
|
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.ct !== undefined, 'should be migrated to encrypted format')
|
||||||
assertTrue(stored.iv !== undefined)
|
assertTrue(stored.iv !== undefined)
|
||||||
})
|
})
|
||||||
@@ -255,7 +255,7 @@ describe('ConversationsService.hashPublicKey', () => {
|
|||||||
|
|
||||||
describe('Per-listing keypair management', () => {
|
describe('Per-listing keypair management', () => {
|
||||||
asyncTest('generateListingKeyPair creates and stores keypair', async () => {
|
asyncTest('generateListingKeyPair creates and stores keypair', async () => {
|
||||||
localStorage.removeItem('dgray_listing_keys')
|
localStorage.removeItem('kashilo_listing_keys')
|
||||||
await cryptoService.unlock(TEST_UUID)
|
await cryptoService.unlock(TEST_UUID)
|
||||||
|
|
||||||
const publicKey = await cryptoService.generateListingKeyPair('test-listing-1')
|
const publicKey = await cryptoService.generateListingKeyPair('test-listing-1')
|
||||||
@@ -326,7 +326,7 @@ describe('Per-listing keypair management', () => {
|
|||||||
await cryptoService.generateListingKeyPair('temp-listing')
|
await cryptoService.generateListingKeyPair('temp-listing')
|
||||||
|
|
||||||
cryptoService.destroyKeyPair()
|
cryptoService.destroyKeyPair()
|
||||||
assertEquals(localStorage.getItem('dgray_listing_keys'), null)
|
assertEquals(localStorage.getItem('kashilo_listing_keys'), null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>dgray.io - Tests</title>
|
<title>kashilo.com - Tests</title>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--color-bg: #1a1a1a;
|
--color-bg: #1a1a1a;
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="results">
|
<div id="results">
|
||||||
<h1>🧪 dgray.io Test Suite</h1>
|
<h1>🧪 kashilo.com Test Suite</h1>
|
||||||
<p class="loading">Running tests...</p>
|
<p class="loading">Running tests...</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
renderResults(container)
|
renderResults(container)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<h1>🧪 dgray.io Test Suite</h1>
|
<h1>🧪 kashilo.com Test Suite</h1>
|
||||||
<p style="color: var(--color-failed)">
|
<p style="color: var(--color-failed)">
|
||||||
Error loading tests: ${error.message}
|
Error loading tests: ${error.message}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ describe('getFileUrl', () => {
|
|||||||
|
|
||||||
test('builds basic URL without options', () => {
|
test('builds basic URL without options', () => {
|
||||||
const url = getFileUrl('abc-123')
|
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', () => {
|
test('appends width parameter', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user