blob: baa136b81f6697183840e7134fbbc483ab1adf98 [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <base/callback.h>
#include <base/memory/weak_ptr.h>
#include <chromeos/dbus/service_constants.h>
#include "biod/proto_bindings/constants.pb.h"
namespace biod {
// A BiometricsManager object represents one biometric input device and all of
// the records registered with it. At a high level, there are 3 operations that
// are supported: 1) enrolling new record objects, 2) authenticating against
// those record objects, and 3) destroying all record objects made from this
// BiometricsManager. For DestroyAllRecords the operation is as simple as
// calling the function. For the other operations, the BiometricsManager object
// must be entered into AuthSession or EnrollSession, which is represented
// in code by the return of the session objects. EnrollSession and AuthSession
// can be thought of as session objects that are ongoing as long as the unique
// pointers remain in scope and the End/Cancel methods haven't been called. It's
// undefined what StartEnrollSession or StartAuthSession will do if there is an
// valid outstanding EnrollSession or AuthSession object in the wild.
class BiometricsManager {
struct EnrollSessionEnder {
void operator()(BiometricsManager* biometrics_manager) {
struct AuthSessionEnder {
void operator()(BiometricsManager* biometrics_manager) {
// Invokes the function object F with a given BiometricsManager object when
// this session (EnrollSession or AuthSession) object goes out of scope. It's
// possible that this will do nothing in the case that the session has ended
// due to failure/finishing or the BiometricsManager object is no longer
// valid.
template <typename F>
class Session {
Session() = default;
Session(Session<F>&& rhs) : biometrics_manager_(rhs.biometrics_manager_) {
explicit Session(const base::WeakPtr<BiometricsManager>& biometrics_manager)
: biometrics_manager_(biometrics_manager) {}
~Session() { End(); }
Session<F>& operator=(Session<F>&& rhs) {
biometrics_manager_ = rhs.biometrics_manager_;
return *this;
explicit operator bool() const { return biometrics_manager_; }
// Has the same effect of letting this object go out of scope, but allows
// one to reuse the storage of this object.
void End() {
if (biometrics_manager_) {
F f;
base::WeakPtr<BiometricsManager> biometrics_manager_;
// Returned by StartEnrollSession to ensure that EnrollSession eventually
// ends.
using EnrollSession = Session<EnrollSessionEnder>;
// Returned by StartAuthSession to ensure that AuthSession eventually
// ends.
using AuthSession = Session<AuthSessionEnder>;
// Represents a record previously registered with this BiometricsManager in an
// EnrollSession. These objects can be retrieved with GetRecords.
class Record {
virtual ~Record() {}
virtual const std::string& GetId() const = 0;
virtual const std::string& GetUserId() const = 0;
virtual const std::string& GetLabel() const = 0;
// Returns true on success.
virtual bool SetLabel(std::string label) = 0;
// Returns true on success.
virtual bool Remove() = 0;
virtual ~BiometricsManager() {}
virtual BiometricType GetType() = 0;
// Puts this BiometricsManager into EnrollSession mode, which can be ended by
// letting the returned session fall out of scope. The user_id is arbitrary
// and is given to AuthScanDone callbacks in the AuthSession object. The label
// should be human readable and ideally from the user themselves. The label
// can be read and modified from the Record objects. This will fail if ANY
// other mode is active. Returns a false EnrollSession on failure.
virtual EnrollSession StartEnrollSession(std::string user_id,
std::string label) = 0;
// Puts this BiometricsManager into AuthSession mode, which can be ended by
// letting the returned session fall out of scope. This will fail if ANY other
// mode is active. Returns a false AuthSession on failure.
virtual AuthSession StartAuthSession() = 0;
// Gets the records registered with this BiometricsManager. Some records will
// naturally be unaccessible because they are currently in an encrypted state,
// so those will silently be left out of the returned vector.
virtual std::vector<std::unique_ptr<Record>> GetRecords() = 0;
// Irreversibly destroys records registered with this BiometricsManager,
// including currently encrypted ones. Returns true if successful.
// TODO(mqg): right now it does not destroy the encrypted records, but that is
// the goal for the future.
virtual bool DestroyAllRecords() = 0;
// Remove all decrypted records from memory. Still keep them in storage.
virtual void RemoveRecordsFromMemory() = 0;
// Read all the records for each of the users in the set. Return true if
// successful.
virtual bool ReadRecords(const std::unordered_set<std::string>& user_ids) = 0;
// The callbacks should remain valid as long as this object is valid.
// Enrollment progress passed to EnrollScanDoneCallback.
struct EnrollStatus {
// True if enrollment is complete (which may take multiple scans).
bool done;
// Percentage of the enrollment process that is complete, in the range [0,
// 100]. -1 if the sensor library did not provide a percentage.
int percent_complete;
// Invoked from EnrollSession mode whenever the user attempts a scan. The
// first parameter ScanResult tells whether the scan was successful. The
// second parameter EnrollStatus indicates whether the enrollment is complete.
// It may take multiple successful scans before enrollment is complete. When
// the record is complete, EnrollSession mode will automatically be ended.
using EnrollScanDoneCallback =
base::Callback<void(ScanResult, const EnrollStatus&)>;
virtual void SetEnrollScanDoneHandler(
const EnrollScanDoneCallback& on_enroll_scan_done) = 0;
// Invoked from AuthSession mode to indicate either a bad scan of any kind, or
// a successful scan. In the case of successful scan, AttemptMatches is a map
// of user id keys to a vector of record id values.
using AttemptMatches =
std::unordered_map<std::string, std::vector<std::string>>;
using AuthScanDoneCallback = base::Callback<void(ScanResult, AttemptMatches)>;
virtual void SetAuthScanDoneHandler(
const AuthScanDoneCallback& on_auth_scan_done) = 0;
// Invoked during any session to indicate that the session has ended with
// failure. Any EnrollSession record that was underway is thrown away and
// AuthSession will no longer be happening.
using SessionFailedCallback = base::Callback<void()>;
virtual void SetSessionFailedHandler(
const SessionFailedCallback& on_session_failed) = 0;
virtual void EndEnrollSession() = 0;
virtual void EndAuthSession() = 0;
} // namespace biod