Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 1x | import {handler} from '@feasibleone/blong';
import * as account from './account.ts';
export default handler(
({
errors,
lib: {crockfordEncode, verifyPassword},
handler: {accessPermissionList},
}) =>
async function accessCredentialCheck(
params: {username: string; password: string},
$meta: Record<string, unknown>,
): Promise<{
userId: string;
/** Base64 of the raw binary(16) user key — for session creation. */
userKey: string;
/** Active credential id — for session creation. */
credentialId: number;
permissionMap: string;
actions: string[];
}> {
const queryBuilder = this.config?.context?.queryBuilder;
if (!queryBuilder) throw new Error('Database not available');
// 1. Find the user by username (resourceName) and type alias 'access.user'
const user = await queryBuilder
.select('r.resourceId', 'u.userId', 'u.isActive')
.from('core_resource as r')
.join('access_user as u', 'u.userId', 'r.resourceId')
.join('core_type as t', 't.typeId', 'r.typeId')
.where('r.resourceName', params.username)
.where('t.typeAlias', 'access.user')
.first();
if (!user) {
throw errors.userNotFound();
}
if (!user.isActive) {
throw errors.userInactive();
}
// 2. Find the active password credential for this user
const credential = await queryBuilder
.select(
'credentialId',
'credentialHash',
'credentialSalt',
'credentialParamsJSON',
)
.from('access_credential')
.where('userId', user.userId)
.where('credentialType', 'password')
.where('isActive', 1)
.where(function () {
this.whereNull('expiresAt').orWhere('expiresAt', '>', new Date());
})
.first();
if (!credential) {
throw errors.credentialNotFound();
}
// 3. Verify password using the credential parameters stored on the row
// (`credentialParamsJSON` is parsed to an object by the knex adapter;
// fall back to config.password when it was not persisted).
if (
!verifyPassword(
params.password,
credential.credentialHash,
credential.credentialSalt,
credential.credentialParamsJSON,
)
) {
throw errors.credentialsMismatch();
}
// 4. Resolve effective role bits + action names from the materialized core_path
const {permissionMap, actions: actionNames} = await accessPermissionList<{
roleBits: number[];
actions: string[];
permissionMap: string;
}>(
{userId: account.bufToUuid(user.userId)},
$meta,
);
return {
userId: crockfordEncode(user.userId),
userKey: Buffer.from(user.userId).toString('base64'),
credentialId: credential.credentialId,
permissionMap,
actions: actionNames,
};
},
);
|