36 lines
3.0 KiB
TypeScript
36 lines
3.0 KiB
TypeScript
import { useState } from 'react';
|
|
import { Management, button, control } from '@/pages/management/shared';
|
|
import { profileJson } from '@/lib/profile-json';
|
|
import { createOperationKey } from '@/lib/operation-key';
|
|
type Plan = {approval_id:string;requested_by:number;second_user_id:number;reason:string;expires_at:string;consumed:boolean;expired:boolean;code_current:boolean;can_confirm:boolean;mfa_confirmed_in_session:boolean;hash:string;target:{database:string;port:number}};
|
|
export default function BootstrapConfirmation(plan:Plan) {
|
|
const [key] = useState(createOperationKey);
|
|
const [reason,setReason] = useState('');
|
|
const [confirmed,setConfirmed] = useState(false);
|
|
const [busy,setBusy] = useState(false);
|
|
const [done,setDone] = useState(plan.consumed);
|
|
const [message,setMessage] = useState('');
|
|
async function confirm() {
|
|
setBusy(true);setMessage('');
|
|
try {
|
|
await profileJson('/management/profile-install/bootstrap/'+plan.approval_id+'/confirm',{hash:plan.hash,confirm:confirmed,idempotency_key:key,reason});
|
|
setDone(true);setMessage('Dupla inicializada por confirmação cruzada. Apenas estas duas contas foram designadas; nenhuma flag foi alterada. Inicie uma nova sessão.');
|
|
} catch(error) {setMessage(error instanceof Error?error.message:'Resposta indisponível. Recupere este pedido antes de repetir.');}
|
|
finally {setBusy(false);}
|
|
}
|
|
return <Management title="Confirmar os dois titulares">
|
|
<p>Base {plan.target.database}:{plan.target.port}</p>
|
|
<p>Pedido apresentado pela conta {plan.requested_by}; confirmação reservada à conta {plan.second_user_id}.</p>
|
|
<p>Fundamento do pedido: {plan.reason}</p><p>Expira em {plan.expires_at}.</p>
|
|
<p>O pedido não atribui privilégios. A confirmação é uma operação distinta, com MFA e auditoria. Não altera a regra de substituição posterior.</p>
|
|
{plan.expired && <p role="alert">Pedido expirado. Prepare novo pedido autorizado.</p>}
|
|
{!plan.code_current && <p role="alert">Revisão ou destino alterados. Este pedido não pode ser confirmado.</p>}
|
|
{!plan.mfa_confirmed_in_session && <p role="alert">Conclua MFA nesta sessão antes de confirmar.</p>}
|
|
{!plan.can_confirm && !done && <p>Esta conta pode consultar, mas não confirmar o pedido.</p>}
|
|
<label className="block">Fundamento da confirmação<textarea className={control} minLength={20} maxLength={1000} value={reason} onChange={e=>setReason(e.target.value)}/></label>
|
|
<label className="block"><input type="checkbox" checked={confirmed} onChange={e=>setConfirmed(e.target.checked)}/> Confirmo apenas estas duas contas e esta base</label>
|
|
<button className={button} disabled={busy||done||!plan.can_confirm||!plan.mfa_confirmed_in_session||!confirmed||reason.length<20} onClick={()=>void confirm()}>Confirmar designação cruzada</button>
|
|
<p role="status">{done?'Pedido consumido; não reinicializar. ':''}{message}</p>
|
|
</Management>;
|
|
}
|