- Access Control module: SMS/Email/TOTP/Hardware-token MFA factor management - OTP Audit Logs module under Admin menu (list + detail) with 401/403 handling - Two-factor authentication login flow updates - Client KYC, India address, family-members, ckyc, nominee enhancements - New shared KYC helpers (kyc-proof-types, kyc-upload-helper.service) - User create/edit/view enhancements - Shell navigation: OTP Audit Logs entry under real Admin menu
98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
/**
|
|
* Copyright since 2025 Mifos Initiative
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
import { Injectable, inject } from '@angular/core';
|
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
import { Observable } from 'rxjs';
|
|
|
|
export interface OtpGenerateResponse {
|
|
success: boolean;
|
|
otpId?: number;
|
|
otpReference?: string;
|
|
message?: string;
|
|
}
|
|
|
|
export interface OtpVerifyResponse {
|
|
verified: boolean;
|
|
message?: string;
|
|
}
|
|
|
|
export type MfaFactorType = 'SMS' | 'EMAIL' | 'TOTP' | 'TOKEN';
|
|
|
|
export interface MfaFactor {
|
|
id?: number;
|
|
factorType: MfaFactorType;
|
|
destination?: string;
|
|
secret?: string;
|
|
serial?: string;
|
|
verified: boolean;
|
|
verifiedOn?: string;
|
|
otpLogId?: number;
|
|
}
|
|
|
|
/**
|
|
* Wraps the login-OTP endpoints (LincPay SMS + SMTP email) plus the
|
|
* MFA-factor persistence endpoints used by Access Control.
|
|
*/
|
|
@Injectable({ providedIn: 'root' })
|
|
export class AccessControlService {
|
|
private http = inject(HttpClient);
|
|
|
|
// ───── Mobile OTP (LincPay) ─────
|
|
sendMobileOtp(username: string): Observable<OtpGenerateResponse> {
|
|
return this.http.post<OtpGenerateResponse>('/login/otp/generate', { username });
|
|
}
|
|
|
|
verifyMobileOtp(otpId: number, otp: string): Observable<OtpVerifyResponse> {
|
|
return this.http.post<OtpVerifyResponse>('/login/otp/verify', { otpId, otp });
|
|
}
|
|
|
|
// ───── Email OTP (SMTP) ─────
|
|
sendEmailOtp(username: string): Observable<OtpGenerateResponse> {
|
|
return this.http.post<OtpGenerateResponse>('/login/otp/email/generate', { username });
|
|
}
|
|
|
|
verifyEmailOtp(otpId: number, otp: string): Observable<OtpVerifyResponse> {
|
|
return this.http.post<OtpVerifyResponse>('/login/otp/email/verify', { otpId, otp });
|
|
}
|
|
|
|
// ───── MFA factors persistence (NEW backend endpoints) ─────
|
|
/**
|
|
* Marker header that tells our Fineract security filter to return a plain
|
|
* 401 (no `WWW-Authenticate: Basic`) so the browser doesn't pop up its
|
|
* native Basic-Auth dialog when the endpoint isn't wired up yet.
|
|
*/
|
|
private silentHeaders = new HttpHeaders({ 'X-Requested-With': 'XMLHttpRequest' });
|
|
|
|
/** List the signed-in user's MFA factors. */
|
|
listMyFactors(): Observable<MfaFactor[]> {
|
|
return this.http.get<MfaFactor[]>('/mfa/factors', { headers: this.silentHeaders });
|
|
}
|
|
|
|
/**
|
|
* Persist a verified factor. Backend should set `verified=true`,
|
|
* `verified_on=NOW()`, and link to the matching `m_otp_log` row.
|
|
*/
|
|
saveFactor(payload: {
|
|
factorType: MfaFactorType;
|
|
destination?: string;
|
|
secret?: string;
|
|
serial?: string;
|
|
otpId?: number;
|
|
}): Observable<MfaFactor> {
|
|
return this.http.post<MfaFactor>('/mfa/factors', payload, { headers: this.silentHeaders });
|
|
}
|
|
|
|
/** Disable a factor (logical delete — sets `disabled_on`). */
|
|
disableFactor(factorId: number): Observable<{ resourceId: number }> {
|
|
return this.http.delete<{ resourceId: number }>(`/mfa/factors/${factorId}`, {
|
|
headers: this.silentHeaders
|
|
});
|
|
}
|
|
}
|