API v1
Base: https://eclair.kayzen-lyon.com/api/v1. JSON em todo o lado, respostas nunca guardadas em cache. Os dados binários estão em base64url sem preenchimento. openapi.json
Regra de ouro: cifre antes de chamar a API. Nunca envie a chave da ligação, o PIN nem o texto em claro. O mais simples é utilizar o nosso cliente JavaScript (pacote api-client) ou a CLI.
Rotas
| Método | Rota | Finalidade |
|---|---|---|
POST | /secrets | Stocker un secret déjà chiffré |
POST | /secrets/{id}/preview | Libellé chiffré et indicateurs, sans le contenu |
POST | /secrets/{id}/reveal | Révéler (consomme une lecture) |
GET | /manage/{id} | Statut et historique (accusé de lecture) |
DELETE | /manage/{id} | Détruire avant lecture |
POST | /uploads | Ouvrir un envoi de fichiers chiffrés |
POST | /uploads/{id}/parts | URL présignée (5 min) pour une partie |
POST | /requests | Créer une demande de secret (lien de dépôt) |
POST | /requests/{id}/deposits | Déposer un contenu chiffré pour le demandeur |
GET | /requests/{id}/deposits | Lister les dépôts (demandeur) ou vérifier que le lien est ouvert (sans jeton) |
DELETE | /requests/{id} | Fermer la demande et supprimer les dépôts |
POST | /abuse | Signaler un lien abusif |
POST | /webhooks | Enregistrer un webhook https |
DELETE | /webhooks/{id} | Supprimer un webhook |
POST | /domains | Réserver un domaine personnalisé |
GET | /domains/{domain} | État d'un domaine |
POST | /domains/{domain} | Vérifier l'enregistrement TXT et rattacher le domaine |
DELETE | /domains/{domain} | Libérer le domaine |
GET | /config | Limites de l'instance |
GET | /health | Santé du service |
Exemplo (TypeScript, cifragem local)
import { sendSecret, parseSecretLink, receiveSecret } from "@sesame-eclair/api-client";
const options = { baseUrl: "https://eclair.kayzen-lyon.com" };
// Encrypts in this process, then uploads only the ciphertext.
const sent = await sendSecret(options, {
content: { v: 1, type: "text", text: "DB_PASSWORD=..." },
views: 1,
ttlSeconds: 3600,
});
if (sent.ok) console.log(sent.url, sent.manageUrl);
// Recipient side: the key comes from the link fragment.
const link = parseSecretLink(sent.ok ? sent.url : "")!;
const received = await receiveSecret(options, link);Códigos de estado
404— a mesma resposta para segredos desconhecidos, expirados, já lidos ou destruídos.401— PIN errado, com attemptsLeft.403— access_denied: a rede ou o país do leitor não cumpre as restrições do segredo. O segredo fica intacto.423— ainda não legível (revelação diferida), com availableAt.429— demasiados pedidos, tente novamente dentro de uma hora.
Webhooks
Registe um URL https com POST /webhooks e passe depois webhookId ao criar o segredo. Recebe { event, secretId, at } para created, revealed, burned, revoked e expired: nunca o conteúdo. O signingSecret é mostrado uma única vez; verifique cada chamada da seguinte forma:
import { createHmac, timingSafeEqual } from "node:crypto";
// header = request.headers["eclair-signature"], body = raw request body (string)
function verify(header: string, body: string, signingSecret: string): boolean {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay window
const expected = createHmac("sha256", Buffer.from(signingSecret, "base64url"))
.update(`${t}.${body}`)
.digest();
return timingSafeEqual(expected, Buffer.from(v1, "hex"));
}Restrições de acesso
accessRules: { cidrs: ["203.0.113.0/24"], countries: ["FR"] } limita a abertura a redes ou países (máximo de 20 entradas cada). A verificação é feita antes de qualquer envio do texto cifrado; um país desconhecido é recusado assim que exista uma regra de país.
Domínio personalizado
POST /domains reivindica um domínio e devolve um registo TXT de verificação e um CNAME. Depois de criados, POST /domains/{domain} verifica o TXT e associa o domínio; o certificado TLS é emitido automaticamente. A página Domínio personalizado faz tudo isto por si.