Ir para o conteúdo
Bondry

Programa de publicadores

Registre o seu módulo, publique uma versão, receba o pacote assinado e ouça os eventos que o seu servidor precisa.

Nós não hospedamos o seu módulo. Você vende e distribui onde quiser: site próprio, loja própria, marketplace, revendedor. O que fica aqui é a verdade sobre aquele arquivo, e é essa verdade que o instalador do comprador confere antes de extrair um único byte.

O que você faz, uma vez#

  1. Cadastre o artefato na sua conta, em Publicação. O slug é reservado aqui, e não na primeira versão: ele é o nome que o seu módulo leva para toda instalação, vai para o seu module.json e nunca muda. Nomes do nosso namespace (bondry-, core, admin, designer, members, lms) são recusados.
  2. Gere o token de publicação. Ele é um id bkp_ mais um segredo mostrado uma vez. Um token por artefato, revogável na hora. Revogar não derruba o que já foi publicado: impede o próximo anúncio.
  3. Informe a URL de webhook se quiser que o seu servidor ouça de nós. Só https, porta 443, e o nome precisa resolver para endereços públicos.

O que o seu servidor faz, a cada versão#

Tudo é assinado com o mesmo envelope que você já conhece da API de licença, então não há nada novo para aprender:

Código
X-Bondry-Key:        bkp_3f7a91c25e08
X-Bondry-Timestamp:  1789459200
X-Bondry-Nonce:      3f7a91c25e0844b1
X-Bondry-Signature:  hex(hmac_sha256(segredo, METHOD\nPATH\nTIMESTAMP\nNONCE\nsha256(corpo)))

A janela do timestamp é de 300 segundos, o nonce é de uso único e o corpo entra na assinatura pelo sha256, então nem um byte muda no caminho.

Chamada O que faz
POST /v1/publisher/artifacts/{slug} Atualiza nome, resumo, descrição por idioma, site e canal de suporte. Idempotente: campo que você não manda é campo que não mexemos. O inglês é obrigatório em todo texto por idioma
POST /v1/publisher/artifacts/{slug}/releases Anuncia uma versão: version, min_core, max_core, php, notes por idioma, size, sha256
PUT /v1/publisher/releases/{version}/package Envia o zip, cru no corpo, até 40 MB. O sha256 precisa bater com o anunciado
GET /v1/publisher/artifacts/{slug} Tudo o que o seu pipeline precisa para decidir se segue: estado da revisão, versão publicada, hash de validação, último anúncio
GET /v1/publisher/releases/{version}/package Depois da aprovação, uma URL assinada e curta para buscar o zip assinado
GET /v1/publisher/releases/{version}/hash O hash de validação daquela versão

Anunciar é barato e pode ser repetido; subir 40 MB, não, e é por isso que são duas chamadas. Um anúncio sem pacote expira sozinho em sete dias, e aquele número de versão volta a ficar livre.

Toda recusa diz o campo, o que chegou e o que se esperava. "Invalid payload" não é mensagem.

A revisão#

A metade automática roda assim que o seu pacote chega: nenhum caminho para fora do arquivo, nenhum link simbólico, nenhuma bomba de descompressão, tamanho no teto, manifesto válido com o slug cadastrado e a versão anunciada, versão que avança, min_core que existe, tradução do inglês presente, e a varredura estática que acende bandeira em eval, literal grande dentro de base64_decode, shell_exec, URL com IP fixo e código ofuscado.

Bandeira não reprova nada sozinha: código legítimo usa todas elas de vez em quando. Ela vai para um revisor humano, com o arquivo e a linha exata.

A metade humana olha o seu manifesto, as permissões e os ganchos que você declara, as migrações e os arquivos de rota do pacote, as bandeiras e a diferença em relação à sua versão anterior. A decisão é aprovar, reprovar, pedir mudança ou suspender, e todas elas, menos a aprovação, vêm com um motivo escrito que chega até você palavra por palavra.

"Pedir mudança" devolve a versão para rascunho, que é o único estado em que o seu servidor pode enviar o pacote da mesma versão de novo.

O zip assinado é seu para distribuir#

Aprovada, assinamos o seu zip com a chave de pacote do Bondry e gravamos o sha256 do arquivo assinado. Esse hash é a identidade daquela versão para sempre.

O zip assinado é o seu zip mais duas entradas na raiz:

Código
bondry-artifact.json     {"slug":…,"version":…,"publisher":…,"files":{"<caminho>":"<sha256>"}}
bondry-artifact.sig      base64 de RSA-SHA256 sobre o manifesto canônico

A lista de arquivos cobre toda entrada do seu zip original, e o instalador confere os dois sentidos: nada do zip fora da lista, nada da lista faltando no zip. Sem isso, bastaria acrescentar um .php ao pacote depois de assinado e a assinatura continuaria conferindo.

Você busca o arquivo assinado na sua conta ou pela API, e apagamos a nossa cópia assim que você baixa, e em todo caso sete dias depois da aprovação, com um e-mail no terceiro dia se você ainda não tiver buscado. O que fica aqui é o manifesto, a assinatura, o hash e as notas. O arquivo é seu, e a guarda também.

O que o instalador do comprador faz#

Ele calcula o sha256 do arquivo que está na mão dele, confere a assinatura embutida com a chave pública que já carrega para os updates do core, e pergunta ao registro:

Código
GET /v1/artifacts/{slug}/verify?version=1.4.2&sha256=<64 hex>

Sem credencial, uma de três respostas, sempre HTTP 200:

Resposta O que o comprador vê
verified "Arquivo conferido com o registro do Bondry, versão 1.4.2 do publicador <você>", e a instalação segue
altered A tela vermelha: este arquivo não é o que o autor publicou. A instalação recusa por padrão
unknown Não consta no registro: tratado como um zip qualquer baixado da internet

Uma versão suspensa responde unknown. Sem rede, a assinatura embutida ainda vale e o instalador diz que não conseguiu confirmar: falta de rede nunca é acusação, e também não é aprovação silenciosa.

Os eventos que você recebe#

Você cadastra uma URL https por artefato e nós a chamamos:

Evento Quando
artifact.approved / artifact.rejected a decisão sobre o seu cadastro
release.approved a versão passou na revisão e está publicada
release.rejected reprovada, ou devolvida para mudança, com o motivo
release.suspended tirada do ar depois de publicada, com o motivo
package.altered uma instalação licenciada recebeu um arquivo que não bate com o seu hash aprovado

O corpo:

JSON
{
  "id": "01J8ZC5E7Q2R8VQ1F0M4V8N0PA",
  "type": "release.approved",
  "created_at": "2026-09-17T11:31:55+00:00",
  "data": { "slug": "directory", "version": "1.1.0", "validation_hash": "…" }
}

O id é estável: o reenvio leva o mesmo id, então trate-o como a sua chave de idempotência. Quando um tipo cobre mais de uma decisão, data.decision carrega a palavra exata e data.reason, o motivo escrito.

Como conferir a assinatura#

Assinamos a chamada com o segredo de webhook daquele artefato, no mesmo envelope de cima, com uma diferença: o X-Bondry-Key carrega whk_<12 hex>, o id público do segredo. É assim que o seu lado sabe qual segredo usar depois de uma rotação, e é por isso que vale guardar os seus segredos indexados por esse id.

PHP
$canonical = implode("\n", [
    'POST',
    '/seu/caminho/de/webhook',
    $request->header('X-Bondry-Timestamp'),
    $request->header('X-Bondry-Nonce'),
    hash('sha256', $request->getContent()),
]);

$esperada = hash_hmac('sha256', $canonical, $seuSegredoDe($request->header('X-Bondry-Key')));

if (! hash_equals($esperada, (string) $request->header('X-Bondry-Signature'))) {
    abort(401);
}

Rotacionar o segredo pela sua conta mantém o anterior válido por 24 horas, para você trocar a configuração sem perder evento nenhum.

Responda 2xx em até 10 segundos. Fora disso, tentamos de novo em 1 min, 5 min, 30 min, 2 h, 12 h e 24 h, e depois o endpoint entra em quarentena e você recebe um e-mail. Toda entrega e toda tentativa ficam visíveis na sua conta, com a resposta que o seu servidor deu e um botão para enviar de novo.

Quando alguém distribui uma cópia adulterada#

A chamada de veredito é pública, e por isso ela nunca gera alerta: qualquer pessoa poderia chamá-la mil vezes com um hash inventado, e o registro viraria um amplificador de spam apontado para você.

Quem gera alerta é o evento: uma instalação com licença ativa dizendo que o arquivo que ela recebeu não é o que assinamos. Isso vira o webhook package.altered, um e-mail para você com o hash recebido e o hash que aprovamos, e uma linha na nossa fila, agrupada por artefato e por hash. O mesmo hash adulterado aparecendo em muitas licenças é pirataria em escala, e é exatamente isso que o agrupamento existe para mostrar.

Nada disso revoga coisa alguma sozinho. Quem suspende é gente, com motivo escrito.

Privacidade

Este site usa apenas cookies necessários: sessão, idioma, tema e a verificação anti-spam do hCaptcha nos formulários. Não há rastreamento nem publicidade. Política de privacidade