Pourquoi héberger son propre endpoint ?

iCanText est conçu pour être radicalement décentralisé. Cependant, pour que les utilisateurs puissent se trouver et initier une connexion, un "lieu de rendez-vous" public est nécessaire. C'est le rôle du serveur de signalisation, ou "endpoint".

Par défaut, iCanText utilise l'endpoint https://p.sayseeshow.io. Bien que ce service soit minimaliste et respectueux de la vie privée (il n'enregistre rien), le simple fait de l'utiliser révèle à nos serveurs qu'une tentative de connexion a eu lieu.

En déployant votre propre endpoint sur un serveur que vous contrôlez, vous atteignez un niveau de confidentialité supérieur :

Guide de Déploiement en 3 Étapes

Étape 1 : Prérequis

Ce guide s'adresse à un déploiement sur un hébergement web mutualisé standard. Vous aurez besoin de :

  • Un hébergement web supportant PHP (version 7.4 ou supérieure).
  • La possibilité de créer des fichiers et des dossiers (via FTP ou un gestionnaire de fichiers).
  • La possibilité de créer ou modifier un fichier .htaccess (pour les serveurs Apache).

Étape 2 : Création des Fichiers

Sur votre serveur, créez la structure de dossiers et de fichiers suivante. Par exemple, à la racine de votre site https://votre-domaine.com/ :

/ (racine de votre site)
├── canaux/             (Ce dossier doit avoir les permissions d'écriture, ex: 755)
├── canal.php           (Le script principal)
├── .htaccess           (Le fichier de configuration Apache)
├── cors-handler.php    (Gestionnaire pour les requêtes CORS)
└── cors_config.php     (Configuration des domaines autorisés)
					

Note de sécurité : La configuration CORS ci-dessous est sécurisée car elle n'autorise que des domaines spécifiques. Vous pouvez éditer la liste $allowedOrigins dans cors_config.php pour ajouter vos propres domaines si vous hébergez une version modifiée de l'application iCanText.

Contenu du fichier cors_config.php

Ce fichier centralise les domaines autorisés à se connecter à votre endpoint.

Fichier : cors_config.php

<?php
// Fichier : cors_config.php

$allowedOrigins = [
    'https://sayseeshow.io',
    'https://icansend.com',
    'https://icanphone.com',
    'https://icantext.com',
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';

if (in_array($origin, $allowedOrigins, true)) {
    header("Access-Control-Allow-Origin: $origin");
    header('Access-Control-Allow-Credentials: true');
}

Contenu du fichier cors-handler.php

Ce script gère les requêtes "pre-flight" (OPTIONS) envoyées par les navigateurs.

Fichier : cors-handler.php

<?php
// Fichier : cors-handler.php
// Ce script est appelé par le .htaccess uniquement pour les requêtes OPTIONS.

require_once __DIR__ . '/cors_config.php';

// Les requêtes OPTIONS (pre-flight) n'ont besoin que de ces en-têtes.
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
header('Access-Control-Max-Age: 86400');
header("HTTP/1.1 204 No Content");
exit(0);

Contenu du fichier canal.php

Ce code php utilise la configuration CORS.

Fichier : canal.php

<?php
/*
 * Endpoint de signalisation WebRTC basé sur des fichiers.
 */
 
require_once __DIR__ . '/cors_config.php';

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    require __DIR__ . '/cors-handler.php';
    exit(0);
}

define('MAX_INPUT_SIZE', 15 * 1024);
define('MAX_FILE_SIZE', 150 * 1024);

header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: 0');

$fichier = $_GET['fichier'] ?? '';
if (preg_match('/^[a-zA-Z0-9_-]+$/', $fichier) !== 1) {
    header("HTTP/1.1 400 Bad Request");
    exit('Nom de canal invalide.');
}

$chemin_fichier = __DIR__ . '/canaux/' . basename($fichier);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $contenu = file_get_contents('php://input');

    if (strlen($contenu) > MAX_INPUT_SIZE) {
        header("HTTP/1.1 413 Payload Too Large");
        exit('La charge utile dépasse la limite.');
    }

    if (!$contenu) {
        header("HTTP/1.1 400 Bad Request");
        exit('Aucun contenu reçu.');
    }

    $fp = fopen($chemin_fichier, 'a');
    if (!$fp) {
        header("HTTP/1.1 500 Internal Server Error");
        exit('Impossible d\'ouvrir le fichier de canal.');
    }

    if (flock($fp, LOCK_EX)) {
        clearstatcache(true, $chemin_fichier);
        if (file_exists($chemin_fichier) && filesize($chemin_fichier) + strlen($contenu) > MAX_FILE_SIZE) {
            flock($fp, LOCK_UN);
            fclose($fp);
            header("HTTP/1.1 409 Conflict");
            exit('Le canal est plein.');
        }
        fwrite($fp, $contenu . "\n---\n");
        fflush($fp);
        flock($fp, LOCK_UN);
        fclose($fp);

        header("HTTP/1.1 201 Created");
        exit;
    } else {
        fclose($fp);
        header("HTTP/1.1 503 Service Unavailable");
        exit('Impossible d\'acquérir un verrou.');
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    if (!file_exists($chemin_fichier)) {
        header("HTTP/1.1 404 Not Found");
        exit;
    }

    $fp = fopen($chemin_fichier, 'r');
    if (!$fp) {
        header("HTTP/1.1 500 Internal Server Error");
        exit('Impossible d\'ouvrir le fichier.');
    }

    if (flock($fp, LOCK_EX)) {
        $contenu = stream_get_contents($fp);
        unlink($chemin_fichier);
        flock($fp, LOCK_UN);
        fclose($fp);

        header('Content-Type: text/plain; charset=utf-8');
        echo $contenu;
        exit;
    } else {
        fclose($fp);
        header("HTTP/1.1 503 Service Unavailable");
        exit('Impossible d\'acquérir un verrou.');
    }
}

header("HTTP/1.1 405 Method Not Allowed");
exit;

Contenu du fichier .htaccess

Cette version du .htaccess redirige correctement les requêtes OPTIONS vers le nouveau gestionnaire.

Fichier : .htaccess

RewriteEngine On
Options -Indexes

# 1. Capture du nom du canal dans une variable d'environnement.
RewriteRule ^canaux/([a-zA-Z0-9_-]+)$ - [E=CHANNEL_ID:$1]

# 2. Règle pour les requêtes OPTIONS (pre-flight)
#    On les envoie TOUJOURS au script PHP dédié pour gérer le CORS.
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^canaux/.*$ /cors-handler.php [L]

# 3. Règle pour les requêtes GET (uniquement si le fichier de données existe).
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{DOCUMENT_ROOT}/canaux/%{ENV:CHANNEL_ID} -f
RewriteRule ^canaux/.*$ /canal.php?fichier=%{ENV:CHANNEL_ID} [L,QSA]

# 4. Règle pour les requêtes POST (toujours, pour permettre la création).
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^canaux/.*$ /canal.php?fichier=%{ENV:CHANNEL_ID} [L,QSA]

Étape 3 : Utiliser Votre Endpoint

Une fois les fichiers en place sur votre serveur, votre endpoint est prêt ! Pour l'utiliser, il suffit de construire une URL spécifique pour lancer iCanText et de la partager avec les membres de votre communauté.

L'URL se compose de l'adresse de l'application, suivie d'un fragment # contenant le paramètre endpoint.

Format de l'URL :

https://icantext.com/#&endpoint=https://votre-domaine.com

Remplacez https://votre-domaine.com par l'URL de base où vous avez installé les fichiers. Tous les utilisateurs qui accèdent à iCanText via ce lien utiliseront votre serveur de signalisation privé au lieu de celui par défaut.

Important : Pour garantir la confidentialité, tous les membres de votre espace de travail doivent utiliser la même URL avec votre endpoint personnalisé. Nous vous recommandons de mettre cette URL dans vos favoris ou de la partager comme point d'entrée unique pour votre groupe.

Licence du Code de l'Endpoint

Le code PHP et la configuration .htaccess fournis sur cette page sont des logiciels libres. Nous pensons que la transparence et la collaboration sont essentielles à la sécurité.

Nous avons choisi de publier ce code sous la Licence MIT. C'est l'une des licences open source les plus permissives. Elle vous autorise à :

La licence MIT vous impose une seule obligation simple : inclure l'avis de droit d'auteur original dans toute copie ou modification du logiciel que vous distribuez. L'avis à conserver est le suivant :

Copyright (c) 2025 S.A.S. SAY SEE SHOW ( https://sayseeshow.com )

Le logiciel est fourni "en l'état", sans aucune garantie.