mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 08:43:33 +00:00
[PM-15001] Replace throttle decorator (#15015)
* Add comments to AuditService Abstraction * Replace throttle usage with rxjs mergeMap with concurrent limit * Add test cases for audit service * Remove throttle
This commit is contained in:
@@ -1,21 +1,58 @@
|
||||
import { Subject } from "rxjs";
|
||||
import { mergeMap } from "rxjs/operators";
|
||||
|
||||
import { ApiService } from "../abstractions/api.service";
|
||||
import { AuditService as AuditServiceAbstraction } from "../abstractions/audit.service";
|
||||
import { CryptoFunctionService } from "../key-management/crypto/abstractions/crypto-function.service";
|
||||
import { BreachAccountResponse } from "../models/response/breach-account.response";
|
||||
import { ErrorResponse } from "../models/response/error.response";
|
||||
import { throttle } from "../platform/misc/throttle";
|
||||
import { Utils } from "../platform/misc/utils";
|
||||
|
||||
const PwnedPasswordsApi = "https://api.pwnedpasswords.com/range/";
|
||||
|
||||
export class AuditService implements AuditServiceAbstraction {
|
||||
private passwordLeakedSubject = new Subject<{
|
||||
password: string;
|
||||
resolve: (count: number) => void;
|
||||
reject: (err: any) => void;
|
||||
}>();
|
||||
|
||||
constructor(
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private apiService: ApiService,
|
||||
) {}
|
||||
private readonly maxConcurrent: number = 100, // default to 100, can be overridden
|
||||
) {
|
||||
this.maxConcurrent = maxConcurrent;
|
||||
this.passwordLeakedSubject
|
||||
.pipe(
|
||||
mergeMap(
|
||||
// Handle each password leak request, resolving or rejecting the associated promise.
|
||||
async (req) => {
|
||||
try {
|
||||
const count = await this.fetchLeakedPasswordCount(req.password);
|
||||
req.resolve(count);
|
||||
} catch (err) {
|
||||
req.reject(err);
|
||||
}
|
||||
},
|
||||
this.maxConcurrent, // Limit concurrent API calls
|
||||
),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
@throttle(100, () => "passwordLeaked")
|
||||
async passwordLeaked(password: string): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
this.passwordLeakedSubject.next({ password, resolve, reject });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the count of leaked passwords from the Pwned Passwords API.
|
||||
* @param password The password to check.
|
||||
* @returns A promise that resolves to the number of times the password has been leaked.
|
||||
*/
|
||||
protected async fetchLeakedPasswordCount(password: string): Promise<number> {
|
||||
const hashBytes = await this.cryptoFunctionService.hash(password, "sha1");
|
||||
const hash = Utils.fromBufferToHex(hashBytes).toUpperCase();
|
||||
const hashStart = hash.substr(0, 5);
|
||||
|
||||
Reference in New Issue
Block a user