Ir al contenido

Blog ·

Paneles de marca blanca: qué ve el cliente

Poner el nombre propio en un panel de revendedor es la mitad fácil. La difícil es decidir qué pantallas existen para ese cliente, y hacerlo cumplir.

Por Provibr

Quien revende VPS u hosting acaba encontrándose con clientes que quieren un panel. Quieren reiniciar su propia máquina a las dos de la madrugada en lugar de abrir un ticket, y al revendedor le interesa que lo hagan.

Eso se convierte en dos preguntas que parecen una sola y no lo son. De quién es el nombre que aparece en el panel, y qué partes del panel existen siquiera para esa persona. La primera es marca, y es sobre todo presentación. La segunda es una frontera, y equivocarse ahí es la vía por la que un cliente de un revendedor acaba leyendo la factura de su proveedor.

La marca se detiene donde empiezan los papeles

Reetiquetar un panel significa cambiar el cromo: el logotipo de la barra lateral, el título de página, el favicon, el nombre en el bloque de cuenta. Es una cantidad útil, y es donde se detiene la mayoría de las funciones de marca blanca.

La parte interesante es la lista de cosas que nunca deben llevar el nombre del revendedor.

PantallaDe quién es el nombre que llevaPor qué
Cromo del panel, títulos, faviconDel revendedorEs la relación en la que está el cliente
Declaración de privacidadDe la plataformaUn aviso de tratamiento describe quién trata realmente
Condiciones del servicioDe la plataformaEs el acuerdo de la plataforma, no el del revendedor
Contrato de encargo de tratamientoDe la plataformaLo mismo, y además nombra a los subencargados
Facturas y documentos proformaDe la plataformaEs el registro financiero de una transacción real
La línea de un extracto bancarioDe la plataformaUn registro permanente que nadie puede anotar después

El razonamiento cabe en una frase: un cliente de un cliente nunca debe llegar a creer que tiene un contrato con alguien distinto de la parte con la que lo tiene de verdad. Todo lo que tiene carácter jurídico o financiero lleva el nombre de la contraparte de ese documento, y eso no es una preferencia de diseño.

Más importante que la regla es dónde vive. En nuestro código es una lista de rutas de fichero, y una prueba recorre el árbol de importaciones transitivo desde cada una de ellas, fallando en el instante en que una llega siquiera al módulo de marca. En anchura, para que el error nombre la cadena más corta, que es la que hay que cortar.

Una comprobación de importación directa es demasiado fácil de esquivar: se mete la consulta de marca en un ayudante, se importa el ayudante y listo. Y la guarda se prueba a sí misma en ambos sentidos. Una ruta listada que desaparece es un error y no un salto silencioso, y por separado afirma que el diseño del panel sí alcanza el módulo de marca, porque un resolutor que en silencio no resolviera nada pondría en verde todos los ficheros.

El acceso del propio revendedor nunca lleva otra marca

Hay una segunda regla, menos evidente, que habríamos hecho mal de no dejarla dicha: la marca se aplica únicamente en el dominio propio del cliente.

Cuando el revendedor entra en el host de la plataforma, ve la plataforma y no su propia marca. Ahí es donde viven las facturas, la suscripción y la relación con nosotros. La consulta de marca recae en la versión neutra en el instante en que una petición no está ligada a un dominio de cuenta, de modo que decide exactamente un sitio y ninguna pantalla tiene que acordarse.

La pantalla de gestión de marca muestra una vista previa del cromo que ve el cliente, en lugar de llevar ella misma la otra marca. Suena pedante hasta que se piensa qué enseña la alternativa: un revendedor que ve su propio logotipo encima de su propia factura concluirá, con razón, que sus clientes ven algo parecido.

Un logotipo blanco sobre una barra lateral blanca

El fondo de nuestro panel es blanco, así que un logotipo con fondo transparente y tinta blanca es invisible, y quien lo sube no va a enterarse: lo está mirando en una herramienta de diseño sobre una mesa de trabajo gris.

Lo medimos en lugar de suponerlo, componiendo cada logotipo sobre el color real de la superficie en un navegador sin interfaz:

LogotipoContraste contra la superficie del panel
Tinta oscura, fondo transparente16,46:1
Tinta blanca, fondo transparente1,00:1
Tinta blanca sobre su propia placa opaca17,74:1
Tinta gris claro1,24:1

La fila de 1,00:1 no significa «cuesta leerlo». Cada píxel es idéntico al fondo. El logotipo se dibuja y no hay nada que ver.

De ahí salieron dos decisiones. No hay, deliberadamente, ninguna placa debajo del logotipo, porque eso redibujaría la marca del cliente y le daría un marco a todo logotipo normal con tal de rescatar una excepción. Y la pantalla de subida avisa en lugar de rechazar, porque una marca tiene derecho a ser gris claro.

La medición cuenta la tinta, no el solapamiento. Un logotipo con un margen transparente amplio coincide con el fondo en la mayor parte de su superficie y se ve perfectamente; lo que importa es cuánto de él está dibujado y a qué distancia queda esa tinta del color de la superficie.

La ausencia no es un permiso

Ahora la mitad difícil. ¿Qué pantallas deberían existir para el cliente de un revendedor?

El instinto es modelarlo como permisos: dar un rol al subcliente y marcar menos casillas. Esa es la forma equivocada, por un motivo que solo aparece en los bordes. Los permisos responden a «puede este miembro hacer esto». La pregunta aquí es «existe esta pantalla en este dominio», y las dos se separan en el momento en que el titular de una cuenta entra a mirar su propio panel de cliente. Es el propietario. Toda comprobación de permisos lo deja pasar.

Así que el modelo es una inversión y no un derecho. Una lista fija dice qué superficies están ausentes en un dominio de cuenta: facturación, ajustes de cuenta, tickets, agentes, integraciones, el registro de actividad de la cuenta, la vista de topología, el área de administración de la plataforma, y las páginas de registro y de contraseña olvidada. Ausentes para todo el mundo, propietario incluido.

Tres de esas necesitan justificación, porque el motivo no es el evidente.

Los tickets están ausentes porque el cliente de un revendedor tiene una relación de soporte con el revendedor y no con nosotros. Si esa pantalla existiera, leería una respuesta que nombra a una empresa que, según su propio panel, no existe.

El registro de actividad está ausente porque es el registro de la cuenta, no el de quien lo lee. El resultado honesto no es un registro filtrado sino «esta pantalla no existe aquí». La pestaña de actividad por servidor se queda, porque esa sí está acotada de verdad a una máquina que le pertenece.

La vista de topología demuestra el modelo. Se apoya en el módulo de servidores, y el módulo de servidores es precisamente lo único que un subcliente sí tiene. Una puerta de permisos no descartaría absolutamente nada.

Tres cierres, porque una página no es una frontera

Una comprobación no basta, y cada uno de los tres atrapa lo que los otros no pueden.

El primero está en la propia función de permisos, donde el orden de dos líneas es todo el asunto:

  1. ¿Existe este módulo en esta superficie? Si no, rechazar.
  2. ¿Tiene este rol acceso total? Si es así, permitir.

Poner la prueba de superficie primero es lo que hace que «no existe» gane a «puede todo», y es lo que hace que la inversión se sostenga en todas partes y no solo en las pantallas que alguien recordó.

El segundo es una guarda en cada página bajo esas rutas, que produce un 404 normal. Deliberadamente no recibe ningún argumento: una llamada que nombrara su propia pantalla dejaría que una errata se convirtiese en una puerta abierta en silencio.

El tercero está en el proxy inverso, porque una página no puede atrapar una petición que nunca llega a una página. Un POST a una ruta ausente se rechaza antes de que se ejecute código de página alguno. Las navegaciones se dejan pasar para que se dibuje el 404 de la propia aplicación en lugar de un error pelado del proxy.

Este es el hallazgo que merece la pena llevarse aunque no se construya nada de lo anterior.

Nuestras cookies de sesión son solo de host. Sin atributo Domain, así que una sesión en un dominio de cliente no se envía a otro, ni tampoco al host de la plataforma. Eso es correcto y está probado, incluido el caso negativo en el que activar las cookies entre subdominios hace aparecer un Domain.

Y tampoco es una frontera. El subcliente tiene en su poder su propio testigo de sesión y puede enviarlo a donde quiera con un cliente HTTP de línea de comandos. Solo un navegador habría dicho que no.

Medimos qué permitía eso, y fue peor de lo esperado: un subcliente podía crear una organización completamente nueva con él mismo como propietario, con su propia suscripción de prueba incluida, por dos caminos de código independientes, accesibles desde cuatro puntos de entrada distintos. Cuatro organizaciones, contadas después en la base de datos. En su propio dominio la misma petición la rechazaba el proxy, así que la puerta estaba cerrada por un lado y abierta por el otro.

La reparación no fue añadir comprobaciones a esos dos caminos. Fue poner la frontera en el punto único por el que pasa toda petición autenticada, y el invariante «un subcliente nunca se convierte en propietario de una organización» en la única función que comparten todos los caminos de creación.

La misma ronda encontró en otro sitio la versión general del problema. Una clave de API lleva un rol pero no una superficie. Eso no era explotable, porque la pestaña donde se crea una clave no existe en un dominio de cuenta. Pero eso es un botón escondido y no una frontera, y la diferencia importa el día en que alguien añade una segunda manera de crear claves. El arreglo rechaza al principal en lugar de etiquetar la clave.

Ninguna columna dice «esto es un subcliente»

Una última nota de diseño, porque es de esa clase de decisiones que rinden en silencio.

Un subcliente es una fila de usuario corriente con una dirección de correo reservada de la forma username@<organisation-id>.invalid, más una fila de pertenencia corriente con un perfil de permisos estrecho. No hay ninguna columna booleana que los marque, a propósito: una segunda fuente de verdad puede desincronizarse de la dirección, y entonces dos partes del sistema discrepan sobre quién es alguien.

Como el identificador de la organización va dentro de la dirección, la unicidad sale gratis del índice que ya estaba ahí, y el mismo nombre de usuario puede existir bajo dos revendedores. El formulario de acceso pide un nombre de usuario y toma el identificador de organización del host y no del formulario, así que nadie entra en otra cuenta adivinando un identificador.

Y su dirección nunca se marca como verificada, porque nadie puede verificarla. Esa columna significa «esta dirección pertenece de forma demostrable a esta persona», y ponerla a cierto para una dirección que no llega a ningún buzón trasladaría la mentira a un sitio menos visible.

Lo que no hace

El reetiquetado cubre el cromo. Los textos de la interfaz siguen leyéndose como nuestro producto en el idioma que use quien visita, y fingir lo contrario supondría traducir el vocabulario de un revendedor a nueve idiomas en su nombre. La lista de superficies ausentes es una decisión sobre la forma del producto, no un modelo de seguridad por sí sola: funciona porque los tres cierres que hay detrás sí lo son.

Así funcionan los dominios de cuenta en Provibr, donde el agente se ejecuta en el hardware del propio cliente y solo conecta hacia fuera.

Empiece con un host y un agente

Cree una cuenta, instale el agente con un solo comando y conecte su primer host de Proxmox. El periodo de prueba dura 14 días y no pide ningún dato de pago.