mirror of
https://github.com/directus/directus.git
synced 2026-01-29 01:48:23 -05:00
* Moved refactoring from LDAP branch * Moved Auth into packages * Updated frontend to support custom auth providers and make implementation more flexible * Fixed exception handling and numerous bugs. Also added provider support to graphql * Updated frontend to be able to set provider and identifier * Fixed issue with setting the auth provider in app * Updated package-lock.json * Updated package-lock.json * Cleanup, adding type handling and disabled changing provider * Added title formatting to SSO links * Fixed incorrect type export * Fixed incorrect rc * Update api/src/services/authentication.ts * Updated sub-dependencies to rc87 * Fixed linting errors * Prefer sending provider name as config var * Pass clone of user info to auth provider instead of reference * Moved auth from packages into core * Removed generic login handler * Fixed graphql complaint * Moved exception back to api and cleaned up URLs * Minor tweak * Pulled across improvements from openid branch * Fixed fix that wasn't a fix * Update auth.ts * Update auth.ts * Update authentication.ts * Update login-form.vue * Regression fixes and cleanup * Minor flow improvements * Flipped if and fixed linting warning * Un-expanded object that didn't need to be expanded! * Trimmed auth interface for consistency when verifying passwords * Removed auth-manager, changed login endpoint, broke out SSO links, removed username support, disabled updating external_identifier, generate provider options as part of field generation * Cleaned up some code comments * Use named exports in local driver * Use async defaults for auth abstract class * Use JSON for auth_data field * Move session data blob to directus_sessions * Remove unused export, rename auth->authDriver * Opinionated changes * Move login route registration to driver file * Revert app changes in favor of PR #8277 * Send session token to auth provider and opinionated changes * Added missing translation * Fixed empty elements for users without email * Update api/src/auth/drivers/local.ts * Move pw verify to local driver, remove CRUD * Opinions > logical reasoning * Use session data, cleanup login method on auth serv * Remove useless null * Fixed breaking changes from refactor, and fixed build * Fixed lint warning * Ignore typescript nonsense * Update api/src/services/authentication.ts * Fix provider name passthrough Co-authored-by: Aiden Foxx <aiden.foxx@sbab.se> Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
import { Knex } from 'knex';
|
|
import { authenticator } from 'otplib';
|
|
import getDatabase from '../database';
|
|
import { InvalidPayloadException } from '../exceptions';
|
|
import { ItemsService } from './items';
|
|
import { AbstractServiceOptions, PrimaryKey } from '../types';
|
|
|
|
export class TFAService {
|
|
knex: Knex;
|
|
itemsService: ItemsService;
|
|
|
|
constructor(options: AbstractServiceOptions) {
|
|
this.knex = options.knex || getDatabase();
|
|
this.itemsService = new ItemsService('directus_users', options);
|
|
}
|
|
|
|
async verifyOTP(key: PrimaryKey, otp: string, secret?: string): Promise<boolean> {
|
|
if (secret) {
|
|
return authenticator.check(otp, secret);
|
|
}
|
|
|
|
const user = await this.knex.select('tfa_secret').from('directus_users').where({ id: key }).first();
|
|
|
|
if (!user?.tfa_secret) {
|
|
throw new InvalidPayloadException(`User "${key}" doesn't have TFA enabled.`);
|
|
}
|
|
|
|
return authenticator.check(otp, user.tfa_secret);
|
|
}
|
|
|
|
async generateTFA(key: PrimaryKey): Promise<Record<string, string>> {
|
|
const user = await this.knex.select('email', 'tfa_secret').from('directus_users').where({ id: key }).first();
|
|
|
|
if (user?.tfa_secret !== null) {
|
|
throw new InvalidPayloadException('TFA Secret is already set for this user');
|
|
}
|
|
|
|
if (!user?.email) {
|
|
throw new InvalidPayloadException('User must have a valid email to enable TFA');
|
|
}
|
|
|
|
const secret = authenticator.generateSecret();
|
|
const project = await this.knex.select('project_name').from('directus_settings').limit(1).first();
|
|
|
|
return {
|
|
secret,
|
|
url: authenticator.keyuri(user.email, project?.project_name || 'Directus', secret),
|
|
};
|
|
}
|
|
|
|
async enableTFA(key: PrimaryKey, otp: string, secret: string): Promise<void> {
|
|
const user = await this.knex.select('tfa_secret').from('directus_users').where({ id: key }).first();
|
|
|
|
if (user?.tfa_secret !== null) {
|
|
throw new InvalidPayloadException('TFA Secret is already set for this user');
|
|
}
|
|
|
|
if (!authenticator.check(otp, secret)) {
|
|
throw new InvalidPayloadException(`"otp" is invalid`);
|
|
}
|
|
|
|
await this.itemsService.updateOne(key, { tfa_secret: secret });
|
|
}
|
|
|
|
async disableTFA(key: PrimaryKey): Promise<void> {
|
|
await this.itemsService.updateOne(key, { tfa_secret: null });
|
|
}
|
|
}
|