blob: a718e2c4c70e94cc8d682fa96bdbb5bb6aedfb10 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "faced/face_auth_service_impl.h"
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <absl/status/status.h>
#include <base/files/file_path.h>
#include <base/functional/bind.h>
#include <brillo/cryptohome.h>
#include "faced/authentication_session.h"
#include "faced/enrollment_session.h"
#include "faced/mojom/faceauth.mojom-forward.h"
#include "faced/util/task.h"
namespace faced {
using ::brillo::cryptohome::home::IsSanitizedUserName;
using ::chromeos::faceauth::mojom::AuthenticationSessionConfigPtr;
using ::chromeos::faceauth::mojom::CreateSessionResult;
using ::chromeos::faceauth::mojom::CreateSessionResultPtr;
using ::chromeos::faceauth::mojom::EnrollmentSessionConfigPtr;
using ::chromeos::faceauth::mojom::FaceAuthenticationSession;
using ::chromeos::faceauth::mojom::FaceAuthenticationSessionDelegate;
using ::chromeos::faceauth::mojom::FaceEnrollmentSession;
using ::chromeos::faceauth::mojom::FaceEnrollmentSessionDelegate;
using ::chromeos::faceauth::mojom::Result;
using ::chromeos::faceauth::mojom::SessionCreationError;
using ::chromeos::faceauth::mojom::SessionInfo;
constexpr int kMaxCameraQueueSize = 3;
FaceAuthServiceImpl::FaceAuthServiceImpl(
mojo::PendingReceiver<FaceAuthenticationService> receiver,
DisconnectionCallback disconnect_handler,
FaceServiceManagerInterface& manager,
std::optional<base::FilePath> daemon_store_path)
: receiver_(this, std::move(receiver)), face_service_manager_(manager) {
receiver_.set_disconnect_handler(
base::BindOnce(&FaceAuthServiceImpl::HandleDisconnect,
base::Unretained(this), std::move(disconnect_handler)));
receiver_set_.set_disconnect_handler(base::BindRepeating(
[]() { LOG(INFO) << "FaceAuthenticationService connection closed."; }));
if (daemon_store_path) {
enrollment_storage_ = EnrollmentStorage(daemon_store_path.value());
}
}
void FaceAuthServiceImpl::HandleDisconnect(base::OnceClosure callback) {
receiver_.reset();
PostToCurrentSequence(std::move(callback));
}
void FaceAuthServiceImpl::Clone(
mojo::PendingReceiver<FaceAuthenticationService> receiver) {
receiver_set_.Add(this, std::move(receiver));
}
void FaceAuthServiceImpl::CreateEnrollmentSession(
EnrollmentSessionConfigPtr config,
::mojo::PendingReceiver<FaceEnrollmentSession> receiver,
::mojo::PendingRemote<FaceEnrollmentSessionDelegate> delegate,
CreateEnrollmentSessionCallback callback) {
// If a session is already active, return an error.
if (session_) {
PostToCurrentSequence(base::BindOnce(
std::move(callback),
CreateSessionResult::NewError(SessionCreationError::ALREADY_EXISTS)));
return;
}
// Lease a client for communicating with FaceService.
absl::StatusOr<Lease<brillo::AsyncGrpcClient<faceauth::eora::FaceService>>>
face_service_client = face_service_manager_.LeaseClient();
// Check the client is valid.
if (!face_service_client.ok()) {
PostToCurrentSequence(base::BindOnce(
std::move(callback),
CreateSessionResult::NewError(SessionCreationError::UNKNOWN)));
return;
}
// Create a camera stream.
stream_ =
std::make_unique<QueueingStream<absl::StatusOr<std::unique_ptr<Frame>>>>(
/*max_queue_size=*/kMaxCameraQueueSize);
// Create a new session, and register for callbacks when it is closed.
absl::StatusOr<std::unique_ptr<EnrollmentSession>> session =
EnrollmentSession::Create(
bitgen_, std::move(receiver), std::move(delegate), std::move(config),
std::move(face_service_client.value()), stream_->GetReader());
// TODO(b/246196994): handle session creation error propagation
session_ = std::move(session.value());
create_session_callback_ = std::move(callback);
session_->Start(base::BindOnce(&FaceAuthServiceImpl::CompleteSessionStart,
base::Unretained(this)),
base::BindOnce(&FaceAuthServiceImpl::CompleteSessionDone,
base::Unretained(this)));
}
void FaceAuthServiceImpl::CreateAuthenticationSession(
AuthenticationSessionConfigPtr config,
::mojo::PendingReceiver<FaceAuthenticationSession> receiver,
::mojo::PendingRemote<FaceAuthenticationSessionDelegate> delegate,
CreateAuthenticationSessionCallback callback) {
// If a session is already active, return an error.
if (session_) {
PostToCurrentSequence(base::BindOnce(
std::move(callback),
CreateSessionResult::NewError(SessionCreationError::ALREADY_EXISTS)));
return;
}
// Lease a client for communicating with FaceService.
absl::StatusOr<Lease<brillo::AsyncGrpcClient<faceauth::eora::FaceService>>>
face_service_client = face_service_manager_.LeaseClient();
// Check the client is valid.
if (!face_service_client.ok()) {
PostToCurrentSequence(base::BindOnce(
std::move(callback),
CreateSessionResult::NewError(SessionCreationError::UNKNOWN)));
return;
}
// Create a new session, and register for callbacks when it is closed.
absl::StatusOr<std::unique_ptr<AuthenticationSession>> session =
AuthenticationSession::Create(bitgen_, std::move(receiver),
std::move(delegate), std::move(config),
std::move(face_service_client.value()));
// TODO(b/246196994): handle session creation error propagation
session_ = std::move(session.value());
create_session_callback_ = std::move(callback);
PostToCurrentSequence(base::BindOnce(
&FaceAuthServiceImpl::CompleteSessionStart, base::Unretained(this)));
}
void FaceAuthServiceImpl::CompleteSessionStart() {
// Return session information to the caller.
CreateSessionResultPtr result(CreateSessionResult::NewSessionInfo(
SessionInfo::New(session_->session_id())));
PostToCurrentSequence(
base::BindOnce(std::move(create_session_callback_), std::move(result)));
}
void FaceAuthServiceImpl::CompleteSessionDone(absl::Status status) {
if (!status.ok() && create_session_callback_) {
// Return session error to the caller.
CreateSessionResultPtr result(
CreateSessionResult::NewError(SessionCreationError::UNKNOWN));
PostToCurrentSequence(
base::BindOnce(std::move(create_session_callback_), std::move(result)));
}
session_.reset();
}
void FaceAuthServiceImpl::ListEnrollments(ListEnrollmentsCallback callback) {
PostToCurrentSequence(base::BindOnce(std::move(callback),
enrollment_storage_.ListEnrollments()));
}
void FaceAuthServiceImpl::RemoveEnrollment(const std::string& hashed_username,
RemoveEnrollmentCallback callback) {
if (!IsSanitizedUserName(hashed_username)) {
PostToCurrentSequence(base::BindOnce(std::move(callback), Result::ERROR));
return;
}
if (!enrollment_storage_.RemoveEnrollment(hashed_username).ok()) {
PostToCurrentSequence(base::BindOnce(std::move(callback), Result::ERROR));
return;
}
PostToCurrentSequence(base::BindOnce(std::move(callback), Result::OK));
}
void FaceAuthServiceImpl::ClearEnrollments(ClearEnrollmentsCallback callback) {
if (enrollment_storage_.ClearEnrollments().ok()) {
PostToCurrentSequence(base::BindOnce(std::move(callback), Result::OK));
return;
}
PostToCurrentSequence(base::BindOnce(std::move(callback), Result::ERROR));
}
void FaceAuthServiceImpl::IsUserEnrolled(const std::string& hashed_username,
IsUserEnrolledCallback callback) {
if (!IsSanitizedUserName(hashed_username)) {
PostToCurrentSequence(base::BindOnce(std::move(callback), false));
return;
}
PostToCurrentSequence(
base::BindOnce(std::move(callback),
enrollment_storage_.IsUserEnrolled(hashed_username)));
}
} // namespace faced