Files
qinglong/back/migrations/0024-approved-action-recovery-authorization.ts
T

167 lines
5.7 KiB
TypeScript

import { createHash } from 'crypto';
import { DataTypes, Op } from 'sequelize';
import {
APPROVED_ACTION_RECOVERY_STRONG_ASSURANCES,
MAX_APPROVED_ACTION_RECOVERY_AUTH_AGE_MS,
} from '../runtime/domain/approvedActionRecoveryAuthorization';
import { PROJECT_TABLE } from './0017-project-policy';
import { APPROVED_ACTION_RECOVERY_RESOLUTION_TABLE } from './0022-approved-action-recovery';
import type { Migration } from './types';
export const APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE =
'ApprovedActionRecoveryAuthorizationFacts';
export const APPROVED_ACTION_RECOVERY_AUTHORIZATION_MUTATION_INDEX =
'approved_action_recovery_authorization_mutation_uidx';
export const APPROVED_ACTION_RECOVERY_AUTHORIZATION_PROJECT_INDEX =
'approved_action_recovery_authorization_project_idx';
export const APPROVED_ACTION_RECOVERY_AUTHORIZATION_AUTH_INDEX =
'approved_action_recovery_authorization_auth_idx';
const columns = [
'dispatch_id',
'project_id',
'mutation_id',
'resolved_by_id',
'authentication_id',
'assurance',
'authenticated_at_ms',
'project_version',
'binding_version',
'authorized_at_ms',
'fact_digest',
];
const manifest = {
table: APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
columns,
indexes: [
`${APPROVED_ACTION_RECOVERY_AUTHORIZATION_MUTATION_INDEX}(mutation_id) UNIQUE`,
`${APPROVED_ACTION_RECOVERY_AUTHORIZATION_PROJECT_INDEX}(project_id,authorized_at_ms,dispatch_id)`,
`${APPROVED_ACTION_RECOVERY_AUTHORIZATION_AUTH_INDEX}(authentication_id,authorized_at_ms,dispatch_id)`,
],
constraints: [
'approved_action_recovery_authorization_assurance_check',
'approved_action_recovery_authorization_project_version_check',
'approved_action_recovery_authorization_binding_version_check',
'approved_action_recovery_authorization_recency_check',
],
maxAuthenticationAgeMs: MAX_APPROVED_ACTION_RECOVERY_AUTH_AGE_MS,
};
export const approvedActionRecoveryAuthorizationManifest = manifest;
export const approvedActionRecoveryAuthorizationMigration: Migration = {
id: '0024-approved-action-recovery-authorization',
checksum: createHash('sha256').update(JSON.stringify(manifest)).digest('hex'),
async up({ queryInterface, transaction }) {
await queryInterface.createTable(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
{
dispatch_id: {
type: DataTypes.STRING(64),
allowNull: false,
primaryKey: true,
references: {
model: APPROVED_ACTION_RECOVERY_RESOLUTION_TABLE,
key: 'dispatch_id',
},
onDelete: 'RESTRICT',
onUpdate: 'CASCADE',
},
project_id: {
type: DataTypes.STRING(128),
allowNull: false,
references: { model: PROJECT_TABLE, key: 'id' },
onDelete: 'RESTRICT',
onUpdate: 'CASCADE',
},
mutation_id: { type: DataTypes.STRING(64), allowNull: false },
resolved_by_id: { type: DataTypes.STRING(255), allowNull: false },
authentication_id: { type: DataTypes.STRING(128), allowNull: false },
assurance: { type: DataTypes.STRING(32), allowNull: false },
authenticated_at_ms: { type: DataTypes.BIGINT, allowNull: false },
project_version: { type: DataTypes.INTEGER, allowNull: false },
binding_version: { type: DataTypes.INTEGER, allowNull: false },
authorized_at_ms: { type: DataTypes.BIGINT, allowNull: false },
fact_digest: { type: DataTypes.STRING(64), allowNull: false },
},
{ transaction },
);
await queryInterface.addConstraint(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
{
fields: ['assurance'],
type: 'check',
where: {
assurance: { [Op.in]: APPROVED_ACTION_RECOVERY_STRONG_ASSURANCES },
},
name: 'approved_action_recovery_authorization_assurance_check',
transaction,
},
);
for (const [field, name] of [
[
'project_version',
'approved_action_recovery_authorization_project_version_check',
],
[
'binding_version',
'approved_action_recovery_authorization_binding_version_check',
],
] as const) {
await queryInterface.addConstraint(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
{
fields: [field],
type: 'check',
where: { [field]: { [Op.between]: [1, 2_147_483_647] } },
name,
transaction,
},
);
}
await queryInterface.addConstraint(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
{
fields: ['authenticated_at_ms', 'authorized_at_ms'],
type: 'check',
where: {
authorized_at_ms: {
[Op.gte]: { [Op.col]: 'authenticated_at_ms' },
[Op.lte]: queryInterface.sequelize.literal(
`authenticated_at_ms + ${MAX_APPROVED_ACTION_RECOVERY_AUTH_AGE_MS}`,
),
},
},
name: 'approved_action_recovery_authorization_recency_check',
transaction,
},
);
await queryInterface.addIndex(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
['mutation_id'],
{
name: APPROVED_ACTION_RECOVERY_AUTHORIZATION_MUTATION_INDEX,
unique: true,
transaction,
},
);
await queryInterface.addIndex(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
['project_id', 'authorized_at_ms', 'dispatch_id'],
{
name: APPROVED_ACTION_RECOVERY_AUTHORIZATION_PROJECT_INDEX,
transaction,
},
);
await queryInterface.addIndex(
APPROVED_ACTION_RECOVERY_AUTHORIZATION_TABLE,
['authentication_id', 'authorized_at_ms', 'dispatch_id'],
{
name: APPROVED_ACTION_RECOVERY_AUTHORIZATION_AUTH_INDEX,
transaction,
},
);
},
};