Wizard: add details for Satellite token expiration

This commit adds a more detailed information about when does the token
used in Satellite command expire.
This commit is contained in:
Anna Vítová 2025-05-12 11:51:23 +02:00 committed by Klara Simickova
parent daa6e59bc0
commit 4192ada532
3 changed files with 61 additions and 37 deletions

View file

@ -50,7 +50,7 @@ const SatelliteRegistration = () => {
return (
<>
<SatelliteRegistrationCommand />
<FormGroup label="Certificate authority (CA)" isRequired>
<FormGroup label="Certificate authority (CA) for Satellite" isRequired>
<FileUpload
id="text-file-with-restrictions-example"
type="text"
@ -93,6 +93,12 @@ const SatelliteRegistration = () => {
? 'Certificate was uploaded'
: 'Drag and drop a valid certificate file or upload one'}
</HelperTextItem>
{(isRejected || validated !== 'success') && (
<HelperTextItem>
You can find this certificate at{' '}
<i>http://satellite.example.com</i>/pub/katello-server-ca.crt
</HelperTextItem>
)}
</HelperText>
</FormHelperText>
</FormGroup>

View file

@ -112,6 +112,55 @@ type ValidationState = {
ruleCharacters: HelperTextVariant;
};
export function validateSatelliteToken(
registrationCommand: string | undefined
) {
const errors: Record<string, string> = {};
if (registrationCommand === '' || !registrationCommand) {
errors.command = 'No registration command for Satellite registration';
return errors;
}
try {
const match = registrationCommand?.match(
/Bearer\s+([\w-]+\.[\w-]+\.[\w-]+)/
);
if (!match) {
Object.assign(errors, { command: 'Invalid or missing token' });
} else {
const token = match[1];
const decoded = jwtDecode(token);
const currentTimeSeconds = Date.now() / 1000;
const dayInSeconds = 86400;
if (decoded.exp && decoded.exp < currentTimeSeconds + dayInSeconds) {
const expirationDate = new Date(decoded.exp * 1000);
let relativeTimeString;
const secondsRemaining = decoded.exp - currentTimeSeconds;
if (secondsRemaining < 1) {
relativeTimeString = `is expired`;
} else if (secondsRemaining < 60) {
relativeTimeString = `will expire in less than a minute`;
} else if (secondsRemaining < 3600) {
const minutesLeft = Math.floor(secondsRemaining / 60);
relativeTimeString = `will expire in approximately ${minutesLeft} minute${
minutesLeft > 1 ? 's' : ''
}`;
} else {
const hoursLeftExact = secondsRemaining / 3600;
const numHours = Math.round(hoursLeftExact);
relativeTimeString = `will expire in approximately ${numHours} hour${
numHours > 1 ? 's' : ''
}`;
}
errors.expired = `The token ${relativeTimeString}. Expiration date: ${expirationDate.toString()}. Check out the Satellite documentation to extend the Token lifetime.`;
}
}
} catch {
errors.command = 'Invalid or missing token';
}
return errors;
}
export function useRegistrationValidation(): StepValidation {
const registrationType = useAppSelector(selectRegistrationType);
const activationKey = useAppSelector(selectActivationKey);
@ -154,44 +203,13 @@ export function useRegistrationValidation(): StepValidation {
'Valid certificate must be present if you are registering Satellite.',
});
}
if (registrationCommand === '' || !registrationCommand) {
Object.assign(errors, {
command: 'No registration command for Satellite registration',
});
}
try {
const match = registrationCommand?.match(
/Bearer\s+([\w-]+\.[\w-]+\.[\w-]+)/
);
if (!match) {
Object.assign(errors, { command: 'Invalid or missing token' });
} else {
const token = match[1];
const decoded = jwtDecode(token);
if (decoded.exp) {
const currentTimeSeconds = Date.now() / 1000;
const dayInSeconds = 86400;
if (decoded.exp < currentTimeSeconds + dayInSeconds) {
const expirationDate = new Date(decoded.exp * 1000);
Object.assign(errors, {
expired:
'The token is already expired or will expire by next day. Expiration date: ' +
expirationDate,
});
return {
errors: errors,
disabledNext: caCertificate === undefined,
};
}
}
}
} catch {
Object.assign(errors, { command: 'Invalid or missing token' });
}
const tokenErrors = validateSatelliteToken(registrationCommand);
Object.assign(errors, tokenErrors);
return {
errors: errors,
disabledNext:
Object.keys(errors).length > 0 || caCertificate === undefined,
Object.keys(errors).filter((key) => key !== 'expired').length > 0,
};
}

View file

@ -435,7 +435,7 @@ describe('Registration request generated correctly', () => {
);
const expiredTokenHelper = await screen.findByText(
/The token is already expired or will expire by next day. Expiration date/i
/The token is expired. Expiration date/i
);
await waitFor(() => expect(expiredTokenHelper).toBeInTheDocument());