- Implemented FormStep component for user input (name, email, address). - Created OtpStep component for OTP verification. - Developed SuccessStep component to display success messages based on account creation. - Introduced eligibility-check.store for managing state throughout the eligibility check process. - Added commitlint configuration for standardized commit messages. - Configured knip for workspace management and project structure.
121 lines
3.9 KiB
TypeScript
121 lines
3.9 KiB
TypeScript
import { Injectable, Inject, InternalServerErrorException } from "@nestjs/common";
|
|
import { ConfigService } from "@nestjs/config";
|
|
import { Logger } from "nestjs-pino";
|
|
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
|
|
import type {
|
|
FreebitConfig,
|
|
FreebitAuthRequest,
|
|
FreebitAuthResponse,
|
|
} from "../interfaces/freebit.types.js";
|
|
import { FreebitError } from "./freebit-error.service.js";
|
|
|
|
@Injectable()
|
|
export class FreebitAuthService {
|
|
private readonly config: FreebitConfig;
|
|
private authKeyCache: { token: string; expiresAt: number } | null = null;
|
|
|
|
constructor(
|
|
private readonly configService: ConfigService,
|
|
@Inject(Logger) private readonly logger: Logger
|
|
) {
|
|
this.config = {
|
|
baseUrl:
|
|
this.configService.get<string>("FREEBIT_BASE_URL") || "https://i1.mvno.net/emptool/api",
|
|
oemId: this.configService.get<string>("FREEBIT_OEM_ID") || "PASI",
|
|
oemKey: this.configService.get<string>("FREEBIT_OEM_KEY") || "",
|
|
timeout: this.configService.get<number>("FREEBIT_TIMEOUT") || 30000,
|
|
retryAttempts: this.configService.get<number>("FREEBIT_RETRY_ATTEMPTS") || 3,
|
|
detailsEndpoint:
|
|
this.configService.get<string>("FREEBIT_DETAILS_ENDPOINT") || "/master/getAcnt/",
|
|
};
|
|
|
|
if (!this.config.oemKey) {
|
|
this.logger.warn("FREEBIT_OEM_KEY is not configured. SIM management features will not work.");
|
|
}
|
|
|
|
this.logger.debug("Freebit auth service initialized", {
|
|
baseUrl: this.config.baseUrl,
|
|
oemId: this.config.oemId,
|
|
hasOemKey: !!this.config.oemKey,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the current configuration
|
|
*/
|
|
getConfig(): FreebitConfig {
|
|
return this.config;
|
|
}
|
|
|
|
/**
|
|
* Get authentication key (cached or fetch new one)
|
|
*/
|
|
async getAuthKey(): Promise<string> {
|
|
if (this.authKeyCache && this.authKeyCache.expiresAt > Date.now()) {
|
|
return this.authKeyCache.token;
|
|
}
|
|
|
|
try {
|
|
if (!this.config.oemKey) {
|
|
throw new Error("Freebit API not configured: FREEBIT_OEM_KEY is missing");
|
|
}
|
|
|
|
const request: FreebitAuthRequest = {
|
|
oemId: this.config.oemId,
|
|
oemKey: this.config.oemKey,
|
|
};
|
|
|
|
// Ensure proper URL construction - remove double slashes
|
|
const baseUrl = this.config.baseUrl.replace(/\/$/, "");
|
|
const authUrl = `${baseUrl}/authOem/`;
|
|
|
|
const response = await fetch(authUrl, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
body: `json=${JSON.stringify(request)}`,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const data = (await response.json()) as FreebitAuthResponse;
|
|
const resultCode = data?.resultCode == null ? undefined : String(data.resultCode).trim();
|
|
const statusCode =
|
|
data?.status?.statusCode == null ? undefined : String(data.status.statusCode).trim();
|
|
|
|
if (resultCode !== "100") {
|
|
throw new FreebitError(
|
|
`Authentication failed: ${data.status.message}`,
|
|
resultCode,
|
|
statusCode,
|
|
data.status.message
|
|
);
|
|
}
|
|
|
|
this.authKeyCache = { token: data.authKey, expiresAt: Date.now() + 50 * 60 * 1000 };
|
|
this.logger.log("Successfully authenticated with Freebit API");
|
|
return data.authKey;
|
|
} catch (error: unknown) {
|
|
const message = extractErrorMessage(error);
|
|
this.logger.error("Failed to authenticate with Freebit API", { error: message });
|
|
throw new InternalServerErrorException("Failed to authenticate with Freebit API");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear cached authentication key
|
|
*/
|
|
clearAuthCache(): void {
|
|
this.authKeyCache = null;
|
|
this.logger.debug("Cleared Freebit auth cache");
|
|
}
|
|
|
|
/**
|
|
* Check if we have a valid cached auth key
|
|
*/
|
|
hasValidAuthCache(): boolean {
|
|
return !!(this.authKeyCache && this.authKeyCache.expiresAt > Date.now());
|
|
}
|
|
}
|