fix(admin): dominio trocado ao criar, apelidos escondidos e quota a zero
Criar "lucas@cienciaembarcada.com.br" criava "lucas@lucasrguerra.dev.br". O formulario partia o endereco e deitava fora a metade do dominio, e nao enviava domain_id nenhum -- o servidor caia entao no dominio do admin com sessao iniciada. Passa a ser parte local mais um dominio escolhido de uma lista: a metade que decide o endereco deixa de poder ser descartada em silencio. Apelidos de outros dominios estavam escondidos, e a culpa era minha: procurava so no dominio onde a morada do proprio utilizador vive. Uma caixa recebe postmaster, abuse, dmarc e tlsrpt de varios dominios ao mesmo tempo, por isso o painel mostrava quatro onde entregavam oito. Ha um teste que falha com a consulta antiga. Os apelidos passam a poder ser criados e removidos dentro do modal. O dominio sai do endereco escrito, para nao repetir a armadilha do formulario de cima. USER, DOMAIN_ADMIN e SUPER_ADMIN eram constantes impressas no ecra, logo ficavam em ingles em qualquer idioma. Um papel desconhecido continua a ser mostrado tal como esta guardado, porque quem o ve precisa de saber o que a base de dados tem. A quota estava certa e mal mostrada. used_bytes vale 140771 -- os 137,5 KB reais -- mas a pagina arredondava para megabytes inteiros, portanto qualquer coisa abaixo de 512 KB lia-se "0 / 2 MB" e a barra ficava vazia, calculada sobre os megabytes ja arredondados. Passa a formatar a partir dos bytes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f801894f53
commit
bb12e603a3
9 files changed
+308
-35
No files matched your search
@@ -896,24 +896,31 @@ export async function listAliasesForMailbox(
|
||||
mailboxId: string,
|
||||
): Promise<unknown[] | null> {
|
||||
const { sql, params } = scopeClause(scope, "m.domain_id");
|
||||
const owner = await queryOne<{ email_address: string; domain_id: string }>(
|
||||
`SELECT m.email_address, m.domain_id FROM mailboxes m WHERE m.id = $${params.length + 1} AND ${sql}`,
|
||||
const owner = await queryOne<{ email_address: string }>(
|
||||
`SELECT m.email_address FROM mailboxes m WHERE m.id = $${params.length + 1} AND ${sql}`,
|
||||
[...params, mailboxId],
|
||||
);
|
||||
// Out of scope and non-existent are answered the same way, so the console
|
||||
// of one domain cannot probe for ids belonging to another.
|
||||
if (!owner) return null;
|
||||
|
||||
// Every domain in the caller's scope, not only the one the user's own
|
||||
// address sits in. One mailbox commonly receives postmaster, abuse, dmarc
|
||||
// and tlsrpt for several domains at once, and scoping this to the owner's
|
||||
// domain hid all the others - the panel showed four aliases where eight
|
||||
// were delivering.
|
||||
const { sql: aliasSql, params: aliasParams } = scopeClause(scope, "a.domain_id");
|
||||
return query(
|
||||
`SELECT a.id, a.source_address, a.destination_addresses, a.is_catch_all, a.is_active
|
||||
FROM aliases a
|
||||
WHERE a.domain_id = $1
|
||||
`SELECT a.id, a.source_address, a.destination_addresses, a.is_catch_all, a.is_active,
|
||||
d.name AS domain_name
|
||||
FROM aliases a JOIN domains d ON d.id = a.domain_id
|
||||
WHERE ${aliasSql}
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM unnest(a.destination_addresses) AS dest
|
||||
WHERE lower(dest) = lower($2)
|
||||
WHERE lower(dest) = lower($${aliasParams.length + 1})
|
||||
)
|
||||
ORDER BY a.source_address`,
|
||||
[owner.domain_id, owner.email_address],
|
||||
[...aliasParams, owner.email_address],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -826,6 +826,26 @@ describeDb("auth API against a real database", () => {
|
||||
expect(res.status).toBe(404);
|
||||
});
|
||||
|
||||
// One mailbox commonly receives postmaster, abuse, dmarc and tlsrpt for
|
||||
// several domains at once. Scoping the lookup to the domain the user's own
|
||||
// address sits in hid every alias belonging to the others.
|
||||
it("lists aliases from every domain, not only the user's own", async () => {
|
||||
const mine = `cross-domain-alias@pagedtest-${PAGED_DOMAIN}.invalid`;
|
||||
await query(
|
||||
`INSERT INTO aliases (domain_id, source_address, destination_addresses)
|
||||
VALUES ($1, $2, ARRAY[$3]) ON CONFLICT DO NOTHING`,
|
||||
[PAGED_DOMAIN, mine, userEmail()],
|
||||
);
|
||||
|
||||
const res = await get(`/api/v1/admin/mailboxes/${USER_ID}/aliases`, admin);
|
||||
expect(res.status).toBe(200);
|
||||
const sources = (res.body as unknown as { source_address: string }[]).map((a) => a.source_address);
|
||||
|
||||
// USER_ID lives in DOMAIN_ID; this alias lives in PAGED_DOMAIN and
|
||||
// delivers to them all the same.
|
||||
expect(sources).toContain(mine);
|
||||
});
|
||||
|
||||
it("answers 404 for a user that does not exist rather than leaking the difference", async () => {
|
||||
const res = await get(`/api/v1/admin/mailboxes/44444444-4444-4444-4444-444444444444/aliases`, admin);
|
||||
expect(res.status).toBe(404);
|
||||
|
||||
Reference in new issue
Block a user